복붙노트

[SQL] SQL 최소 순차적 일 액세스를 결정하기 위해?

SQL

SQL 최소 순차적 일 액세스를 결정하기 위해?

다음 사용자 기록 테이블은 주어진 사용자가 (24 시간 UTC 기간) 웹 사이트에 액세스 한 모든 일에 대해 하나 개의 레코드가 포함되어 있습니다. 그것은 많은 수천 개의 레코드 만, 사용자 당 하루에 하나 개의 기록을 가지고 있습니다. 사용자가 해당 일의 웹 사이트에 액세스하지 않은 경우, 레코드가 생성되지 않습니다.

Id      UserId   CreationDate
------  ------   ------------
750997      12   2009-07-07 18:42:20.723
750998      15   2009-07-07 18:42:20.927
751000      19   2009-07-07 18:42:22.283

내가 찾고 사용자가 하루 놓치지 않고 (n)의 연속 일 동안 웹 사이트에 액세스 한있는 나에게 말한다 좋은 성능이 테이블에 SQL 쿼리입니다.

즉, 얼마나 많은 사용자 (하루 전, 또는 하루 후) 연속 날짜가이 표에서 (n)의 기록이? 모든 일이 순서에서 누락 된 경우, 순서는 고장 1 다시 다시 시작해야합니다; 우리는 빈틈이없는 여기에 일의 연속 수를 달성 한 사용자를 찾고 있습니다.

이 쿼리 특정 스택 오버플로 배지 간의 유사성은 물론, 순전히 우연입니다 .. :)

해결법

  1. ==============================

    1.대답은 분명하다 :

    대답은 분명하다 :

    SELECT DISTINCT UserId
    FROM UserHistory uh1
    WHERE (
           SELECT COUNT(*) 
           FROM UserHistory uh2 
           WHERE uh2.CreationDate 
           BETWEEN uh1.CreationDate AND DATEADD(d, @days, uh1.CreationDate)
          ) = @days OR UserId = 52551
    

    편집하다:

    좋아요 여기 내 심각한 대답입니다 :

    DECLARE @days int
    DECLARE @seconds bigint
    SET @days = 30
    SET @seconds = (@days * 24 * 60 * 60) - 1
    SELECT DISTINCT UserId
    FROM (
        SELECT uh1.UserId, Count(uh1.Id) as Conseq
        FROM UserHistory uh1
        INNER JOIN UserHistory uh2 ON uh2.CreationDate 
            BETWEEN uh1.CreationDate AND 
                DATEADD(s, @seconds, DATEADD(dd, DATEDIFF(dd, 0, uh1.CreationDate), 0))
            AND uh1.UserId = uh2.UserId
        GROUP BY uh1.Id, uh1.UserId
        ) as Tbl
    WHERE Conseq >= @days
    

    편집하다:

    [제프 앳 우드]이 좋은 빠른 솔루션이며 수용 할 가치가 있지만, 롭 팔리의 솔루션은 또한 우수하고 틀림없이 더 빠른 (!). 너무 그것을 확인하시기 바랍니다!

  2. ==============================

    2.방법에 대한 (그리고 확인하십시오 확인 세미콜론으로 종료 이전 문) :

    방법에 대한 (그리고 확인하십시오 확인 세미콜론으로 종료 이전 문) :

    WITH numberedrows
         AS (SELECT ROW_NUMBER() OVER (PARTITION BY UserID 
                                           ORDER BY CreationDate)
                    - DATEDIFF(day,'19000101',CreationDate) AS TheOffset,
                    CreationDate,
                    UserID
             FROM   tablename)
    SELECT MIN(CreationDate),
           MAX(CreationDate),
           COUNT(*) AS NumConsecutiveDays,
           UserID
    FROM   numberedrows
    GROUP  BY UserID,
              TheOffset  
    

    우리는 (숫자로) 일의 목록이있는 경우이되는 아이디어 및 ROW_NUMBER는 다음 놓친 일이이 두 목록 약간 더 큰 사이의 오프셋합니다. 그래서 우리는 오프셋 일관성이있는 범위를 찾고 있습니다.

    당신은 임계 값에 대해 "COUNT (*)> (14)를 갖는"이 말에 "ORDER BY NumConsecutiveDays DESC"를 사용하거나 말할 수 ...

    나는이 생각을 시험하지 않았다 - 단지 내 머리 위로 떨어져을 작성. 희망 SQL2005과에서 작동합니다.

    ... 그리고 매우 테이블 이름에 인덱스가 도움이 될 것입니다 (사용자 ID, 만든 날짜)

    편집 : 오프셋을 예약어 밝혀, 그래서 내가 대신 TheOffset을 사용했다.

    편집 : 사용 COUNT (*)에 대한 제안은 매우 유효합니다 - 나는 처음에 있음을 했어야하지만 정말 생각하지 않았습니다. 이전에는 DATEDIFF (하루 분 (에서 CreationDate), 최대 (에서 CreationDate))을 대신 사용 하였다.

  3. ==============================

    3.당신이 테이블 스키마를 변경할 수 있다면, 난 당신이에서 CreationDate로 끝나는 연속 일수로 설정하려는 테이블에 열 LongestStreak을 추가하는 게 좋을 것. 행이 현재의 날이 존재하지 않는 경우 모든 행이 전날이있는 경우, 그것은 당신이 이미하고있는 일에 (유사한 로그인 시간에 테이블을 업데이트하기 쉽습니다, 당신은 확인할 수 있습니다. true의 경우, 당신의 LongestStreak을 증가합니다 새 행, 그렇지 않으면, 당신은 1로 설정합니다)

    당신이 테이블 스키마를 변경할 수 있다면, 난 당신이에서 CreationDate로 끝나는 연속 일수로 설정하려는 테이블에 열 LongestStreak을 추가하는 게 좋을 것. 행이 현재의 날이 존재하지 않는 경우 모든 행이 전날이있는 경우, 그것은 당신이 이미하고있는 일에 (유사한 로그인 시간에 테이블을 업데이트하기 쉽습니다, 당신은 확인할 수 있습니다. true의 경우, 당신의 LongestStreak을 증가합니다 새 행, 그렇지 않으면, 당신은 1로 설정합니다)

    쿼리는이 열을 추가 한 후 명백 할 것이다 :

    if exists(select * from table
              where LongestStreak >= 30 and UserId = @UserId)
       -- award the Woot badge.
    
  4. ==============================

    4.의 라인을 따라 일부 잘 표현 SQL :

    의 라인을 따라 일부 잘 표현 SQL :

    select
            userId,
        dbo.MaxConsecutiveDates(CreationDate) as blah
    from
        dbo.Logins
    group by
        userId
    

    당신은 사용자의 선 (이것은 버그가 조심)에 따라 집계 함수 뭔가 정의 가정 :

    using System;
    using System.Data.SqlTypes;
    using Microsoft.SqlServer.Server;
    using System.Runtime.InteropServices;
    
    namespace SqlServerProject1
    {
        [StructLayout(LayoutKind.Sequential)]
        [Serializable]
        internal struct MaxConsecutiveState
        {
            public int CurrentSequentialDays;
            public int MaxSequentialDays;
            public SqlDateTime LastDate;
        }
    
        [Serializable]
        [SqlUserDefinedAggregate(
            Format.Native,
            IsInvariantToNulls = true, //optimizer property
            IsInvariantToDuplicates = false, //optimizer property
            IsInvariantToOrder = false) //optimizer property
        ]
        [StructLayout(LayoutKind.Sequential)]
        public class MaxConsecutiveDates
        {
            /// <summary>
            /// The variable that holds the intermediate result of the concatenation
            /// </summary>
            private MaxConsecutiveState _intermediateResult;
    
            /// <summary>
            /// Initialize the internal data structures
            /// </summary>
            public void Init()
            {
                _intermediateResult = new MaxConsecutiveState { LastDate = SqlDateTime.MinValue, CurrentSequentialDays = 0, MaxSequentialDays = 0 };
            }
    
            /// <summary>
            /// Accumulate the next value, not if the value is null
            /// </summary>
            /// <param name="value"></param>
            public void Accumulate(SqlDateTime value)
            {
                if (value.IsNull)
                {
                    return;
                }
                int sequentialDays = _intermediateResult.CurrentSequentialDays;
                int maxSequentialDays = _intermediateResult.MaxSequentialDays;
                DateTime currentDate = value.Value.Date;
                if (currentDate.AddDays(-1).Equals(new DateTime(_intermediateResult.LastDate.TimeTicks)))
                    sequentialDays++;
                else
                {
                    maxSequentialDays = Math.Max(sequentialDays, maxSequentialDays);
                    sequentialDays = 1;
                }
                _intermediateResult = new MaxConsecutiveState
                                          {
                                              CurrentSequentialDays = sequentialDays,
                                              LastDate = currentDate,
                                              MaxSequentialDays = maxSequentialDays
                                          };
            }
    
            /// <summary>
            /// Merge the partially computed aggregate with this aggregate.
            /// </summary>
            /// <param name="other"></param>
            public void Merge(MaxConsecutiveDates other)
            {
                // add stuff for two separate calculations
            }
    
            /// <summary>
            /// Called at the end of aggregation, to return the results of the aggregation.
            /// </summary>
            /// <returns></returns>
            public SqlInt32 Terminate()
            {
                int max = Math.Max((int) ((sbyte) _intermediateResult.CurrentSequentialDays), (sbyte) _intermediateResult.MaxSequentialDays);
                return new SqlInt32(max);
            }
        }
    }
    
  5. ==============================

    5.당신이되고 n 개의 행이 필요 연속을 통해 N 일 수 있다는 사실을 이용할 수있는 것 같다.

    당신이되고 n 개의 행이 필요 연속을 통해 N 일 수 있다는 사실을 이용할 수있는 것 같다.

    뭔가 같은 :

    SELECT users.UserId, count(1) as cnt
    FROM users
    WHERE users.CreationDate > now() - INTERVAL 30 DAY
    GROUP BY UserId
    HAVING cnt = 30
    
  6. ==============================

    6.하나의 SQL 쿼리 이렇게하면 너무 나에게 복잡하게 보인다. 저 두 부분으로이 답변을 분해 할 수 있습니다.

    하나의 SQL 쿼리 이렇게하면 너무 나에게 복잡하게 보인다. 저 두 부분으로이 답변을 분해 할 수 있습니다.

  7. ==============================

    7.이 당신에게 그렇게 중요하다면,이 이벤트를 소스 당신에게이 정보를 제공하기 위해 테이블을 구동한다. 필요가 모든 미친 쿼리 기계를 죽일 수 없습니다.

    이 당신에게 그렇게 중요하다면,이 이벤트를 소스 당신에게이 정보를 제공하기 위해 테이블을 구동한다. 필요가 모든 미친 쿼리 기계를 죽일 수 없습니다.

  8. ==============================

    8.당신은 재귀 CTE (SQL 서버 2005 +) 사용할 수 있습니다 :

    당신은 재귀 CTE (SQL 서버 2005 +) 사용할 수 있습니다 :

    WITH recur_date AS (
            SELECT t.userid,
                   t.creationDate,
                   DATEADD(day, 1, t.created) 'nextDay',
                   1 'level' 
              FROM TABLE t
             UNION ALL
            SELECT t.userid,
                   t.creationDate,
                   DATEADD(day, 1, t.created) 'nextDay',
                   rd.level + 1 'level'
              FROM TABLE t
              JOIN recur_date rd on t.creationDate = rd.nextDay AND t.userid = rd.userid)
       SELECT t.*
        FROM recur_date t
       WHERE t.level = @numDays
    ORDER BY t.userid
    
  9. ==============================

    9.조 셀코는에 smarties에 대한 SQL이에 완전한 장 (그것을 실행 호출하고 시퀀스)가 있습니다. 나는 직장에 도착하면 그래서 ... 나는 실제로이 답변 해 드리겠습니다 집에서 그 책이 없습니다. (가정 역사 테이블은 dbo.UserHistory 불러 일의 수는 @Days를하다)

    조 셀코는에 smarties에 대한 SQL이에 완전한 장 (그것을 실행 호출하고 시퀀스)가 있습니다. 나는 직장에 도착하면 그래서 ... 나는 실제로이 답변 해 드리겠습니다 집에서 그 책이 없습니다. (가정 역사 테이블은 dbo.UserHistory 불러 일의 수는 @Days를하다)

    또 다른 리드 실행에 SQL 팀의 블로그에서입니다

    다른 아이디어는 내가 했어,하지만 여기에 작업에 편리하여 SQL 서버가없는이 같은 파티션 ROW_NUMBER와 CTE를 사용하는 것입니다 :

    WITH Runs
    AS
      (SELECT UserID
             , CreationDate
             , ROW_NUMBER() OVER(PARTITION BY UserId
                                 ORDER BY CreationDate)
               - ROW_NUMBER() OVER(PARTITION BY UserId, NoBreak
                                   ORDER BY CreationDate) AS RunNumber
      FROM
         (SELECT UH.UserID
               , UH.CreationDate
               , ISNULL((SELECT TOP 1 1 
                  FROM dbo.UserHistory AS Prior 
                  WHERE Prior.UserId = UH.UserId 
                  AND Prior.CreationDate
                      BETWEEN DATEADD(dd, DATEDIFF(dd, 0, UH.CreationDate), -1)
                      AND DATEADD(dd, DATEDIFF(dd, 0, UH.CreationDate), 0)), 0) AS NoBreak
          FROM dbo.UserHistory AS UH) AS Consecutive
    )
    SELECT UserID, MIN(CreationDate) AS RunStart, MAX(CreationDate) AS RunEnd
    FROM Runs
    GROUP BY UserID, RunNumber
    HAVING DATEDIFF(dd, MIN(CreationDate), MAX(CreationDate)) >= @Days
    

    위는 그것으로,하지만 당신은 그냥 날짜보다 "실행"의 다른 정의가있을 때를위한 뇌 자극으로 왼쪽보다 더 열심히 가능성 WAY입니다.

  10. ==============================

    10.SQL 서버 (N = 100 이하 가정) 2,012 옵션의 커플.

    SQL 서버 (N = 100 이하 가정) 2,012 옵션의 커플.

    ;WITH T(UserID, NRowsPrevious)
         AS (SELECT UserID,
                    DATEDIFF(DAY, 
                            LAG(CreationDate, 100) 
                                OVER 
                                    (PARTITION BY UserID 
                                         ORDER BY CreationDate), 
                             CreationDate)
             FROM   UserHistory)
    SELECT DISTINCT UserID
    FROM   T
    WHERE  NRowsPrevious = 100 
    

    내 샘플 데이터가 있지만 다음은보다 효율적으로 밖으로 일

    ;WITH U
             AS (SELECT DISTINCT UserId
                 FROM   UserHistory) /*Ideally replace with Users table*/
        SELECT UserId
        FROM   U
               CROSS APPLY (SELECT TOP 1 *
                            FROM   (SELECT 
                                           DATEDIFF(DAY, 
                                                    LAG(CreationDate, 100) 
                                                      OVER 
                                                       (ORDER BY CreationDate), 
                                                     CreationDate)
                                    FROM   UserHistory UH
                                    WHERE  U.UserId = UH.UserID) T(NRowsPrevious)
                            WHERE  NRowsPrevious = 100) O
    

    모두 사용자 당 하루에 최대 하나의 기록에서이 있다는 질문에 명시된 제약에 의존하고 있습니다.

  11. ==============================

    11.이 같은?

    이 같은?

    select distinct userid
    from table t1, table t2
    where t1.UserId = t2.UserId 
      AND trunc(t1.CreationDate) = trunc(t2.CreationDate) + n
      AND (
        select count(*)
        from table t3
        where t1.UserId  = t3.UserId
          and CreationDate between trunc(t1.CreationDate) and trunc(t1.CreationDate)+n
       ) = n
    
  12. ==============================

    12.나는 연속적으로 사이트에 액세스하는 사람들 식별하는 간단한 수학 속성을 사용했다. 이 속성은 처음 액세스와 지난 시간의 일의 차이가 액세스 테이블 로그 레코드의 수와 동일해야한다는 것입니다.

    나는 연속적으로 사이트에 액세스하는 사람들 식별하는 간단한 수학 속성을 사용했다. 이 속성은 처음 액세스와 지난 시간의 일의 차이가 액세스 테이블 로그 레코드의 수와 동일해야한다는 것입니다.

    여기에 내가 (이 아니라 다른 데시벨에서 작동한다) 오라클 DB에서 테스트하는 것이 SQL 스크립트는 다음과 같습니다

    -- show basic understand of the math properties 
      select    ceil(max (creation_date) - min (creation_date))
                  max_min_days_diff,
               count ( * ) real_day_count
        from   user_access_log
    group by   user_id;
    
    
    -- select all users that have consecutively accessed the site 
      select   user_id
        from   user_access_log
    group by   user_id
      having       ceil(max (creation_date) - min (creation_date))
               / count ( * ) = 1;
    
    
    
    -- get the count of all users that have consecutively accessed the site 
      select   count(user_id) user_count
        from   user_access_log
    group by   user_id
      having   ceil(max (creation_date) - min (creation_date))
               / count ( * ) = 1;
    

    표 준비 스크립트 :

    -- create table 
    create table user_access_log (id           number, user_id      number, creation_date date);
    
    
    -- insert seed data 
    insert into user_access_log (id, user_id, creation_date)
      values   (1, 12, sysdate);
    
    insert into user_access_log (id, user_id, creation_date)
      values   (2, 12, sysdate + 1);
    
    insert into user_access_log (id, user_id, creation_date)
      values   (3, 12, sysdate + 2);
    
    insert into user_access_log (id, user_id, creation_date)
      values   (4, 16, sysdate);
    
    insert into user_access_log (id, user_id, creation_date)
      values   (5, 16, sysdate + 1);
    
    insert into user_access_log (id, user_id, creation_date)
      values   (6, 16, sysdate + 5);
    
  13. ==============================

    13.

    declare @startdate as datetime, @days as int
    set @startdate = cast('11 Jan 2009' as datetime) -- The startdate
    set @days = 5 -- The number of consecutive days
    
    SELECT userid
          ,count(1) as [Number of Consecutive Days]
    FROM UserHistory
    WHERE creationdate >= @startdate
    AND creationdate < dateadd(dd, @days, cast(convert(char(11), @startdate, 113)  as datetime))
    GROUP BY userid
    HAVING count(1) >= @days
    

    우리는 자정에 시작되도록 (날짜로 변환 (CHAR (11), @StartDate, 113)) 문 캐스트는 날짜의 시간 부분을 제거합니다.

    나는에서 CreationDate 및 사용자 ID 열을 인덱싱하는 것도 생각할 겁니다.

    난 그냥이 당신에게 모든 사용자와 총 연속 일을 말하지 않을 것을 깨달았다. 사용자가 선택한 날짜에서 일의 세트 번호를 방문 한 것이다 그러나 당신을 말할 것이다.

    개정 솔루션 :

    declare @days as int
    set @days = 30
    select t1.userid
    from UserHistory t1
    where (select count(1) 
           from UserHistory t3 
           where t3.userid = t1.userid
           and t3.creationdate >= DATEADD(dd, DATEDIFF(dd, 0, t1.creationdate), 0) 
           and t3.creationdate < DATEADD(dd, DATEDIFF(dd, 0, t1.creationdate) + @days, 0) 
           group by t3.userid
    ) >= @days
    group by t1.userid
    

    나는이 문제를 확인했습니다 그것은 모든 사용자와 모든 날짜를 쿼리합니다. 그것은 스펜서의 1 (농담?) 솔루션을 기반으로하지만, 내 작동된다.

    업데이트 : 두 번째 솔루션에서 처리 날짜를 향상시켰다.

  14. ==============================

    14.이것은 당신이 원하는 일을해야하지만 테스트의 효율성에있는 데이터가 충분하지 않습니다. 컨볼 CONVERT / FLOOR 물건은 날짜 필드 오프 시간 부분을 제거하는 것이다. 당신은 SQL 서버 2008을 사용하는 경우 당신은 CAST (x.CreationDate AS 날짜)를 사용할 수 있습니다.

    이것은 당신이 원하는 일을해야하지만 테스트의 효율성에있는 데이터가 충분하지 않습니다. 컨볼 CONVERT / FLOOR 물건은 날짜 필드 오프 시간 부분을 제거하는 것이다. 당신은 SQL 서버 2008을 사용하는 경우 당신은 CAST (x.CreationDate AS 날짜)를 사용할 수 있습니다.

    DECLARE @Range as INT
    SET @Range = 10
    
    SELECT DISTINCT UserId, CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, a.CreationDate)))
      FROM tblUserLogin a
    WHERE EXISTS
       (SELECT 1 
          FROM tblUserLogin b 
         WHERE a.userId = b.userId 
           AND (SELECT COUNT(DISTINCT(CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, CreationDate))))) 
                  FROM tblUserLogin c 
                 WHERE c.userid = b.userid 
                   AND CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, c.CreationDate))) BETWEEN CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, a.CreationDate))) and CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, a.CreationDate)))+@Range-1) = @Range)
    

    생성 스크립트

    CREATE TABLE [dbo].[tblUserLogin](
        [Id] [int] IDENTITY(1,1) NOT NULL,
        [UserId] [int] NULL,
        [CreationDate] [datetime] NULL
    ) ON [PRIMARY]
    
  15. ==============================

    15.스펜서는 거의 그것을했다,하지만이 작업 코드를해야한다 :

    스펜서는 거의 그것을했다,하지만이 작업 코드를해야한다 :

    SELECT DISTINCT UserId
    FROM History h1
    WHERE (
        SELECT COUNT(*) 
        FROM History
        WHERE UserId = h1.UserId AND CreationDate BETWEEN h1.CreationDate AND DATEADD(d, @n-1, h1.CreationDate)
    ) >= @n
    
  16. ==============================

    16.내 머리, MySQLish의 상단 꺼짐 :

    내 머리, MySQLish의 상단 꺼짐 :

    SELECT start.UserId
    FROM UserHistory AS start
      LEFT OUTER JOIN UserHistory AS pre_start ON pre_start.UserId=start.UserId
        AND DATE(pre_start.CreationDate)=DATE_SUB(DATE(start.CreationDate), INTERVAL 1 DAY)
      LEFT OUTER JOIN UserHistory AS subsequent ON subsequent.UserId=start.UserId
        AND DATE(subsequent.CreationDate)<=DATE_ADD(DATE(start.CreationDate), INTERVAL 30 DAY)
    WHERE pre_start.Id IS NULL
    GROUP BY start.Id
    HAVING COUNT(subsequent.Id)=30
    

    테스트되지 않은, 거의 확실하게 MSSQL에 대한 몇 가지 변환을 필요로하지만 나는 몇 가지 아이디어를주고 있다고 생각합니다.

  17. ==============================

    17.어떻게 탈리 테이블을 사용하여 하나 어떻습니까? 그것은 더 알고리즘 접근 방식을 따르며, 실행 계획은 바람이다. 테이블을 스캔 할 것을 1 'MaxDaysBehind'의 숫자로 tallyTable을 채우십시오 (예. 90, 뒤에 3개월 위해 등을 볼 것이다).

    어떻게 탈리 테이블을 사용하여 하나 어떻습니까? 그것은 더 알고리즘 접근 방식을 따르며, 실행 계획은 바람이다. 테이블을 스캔 할 것을 1 'MaxDaysBehind'의 숫자로 tallyTable을 채우십시오 (예. 90, 뒤에 3개월 위해 등을 볼 것이다).

    declare @ContinousDays int
    set @ContinousDays = 30  -- select those that have 30 consecutive days
    
    create table #tallyTable (Tally int)
    insert into #tallyTable values (1)
    ...
    insert into #tallyTable values (90) -- insert numbers for as many days behind as you want to scan
    
    select [UserId],count(*),t.Tally from HistoryTable 
    join #tallyTable as t on t.Tally>0
    where [CreationDate]> getdate()-@ContinousDays-t.Tally and 
          [CreationDate]<getdate()-t.Tally 
    group by [UserId],t.Tally 
    having count(*)>=@ContinousDays
    
    delete #tallyTable
    
  18. ==============================

    18.미세 조정 빌의 쿼리 A를 비트. 당신은 하루에 단 하나의 로그인을 계산 그룹화하기 전에 날짜를 절단해야 할 수도 있습니다 ...

    미세 조정 빌의 쿼리 A를 비트. 당신은 하루에 단 하나의 로그인을 계산 그룹화하기 전에 날짜를 절단해야 할 수도 있습니다 ...

    SELECT UserId from History 
    WHERE CreationDate > ( now() - n )
    GROUP BY UserId, 
    DATEADD(dd, DATEDIFF(dd, 0, CreationDate), 0) AS TruncatedCreationDate  
    HAVING COUNT(TruncatedCreationDate) >= n
    

    EDITED 대신 변환 (숯 (10)에서 CreationDate 101)의 DATEADD (DD, DATEDIFF (DD, 0에서 CreationDate), 0)를 사용한다.

    @IDisposable 나는 날짜 부분 이전 버전을 사용하고자했지만 내가 대신 변환을 사용하는 거라고 생각 그래서 구문을 찾아 너무 게으른했다. 나는 그것이 큰 영향 감사했다 알고 힘! 지금은 알고있다.

  19. ==============================

    19.같이가는 스키마를 가정 :

    같이가는 스키마를 가정 :

    create table dba.visits
    (
        id  integer not null,
        user_id integer not null,
        creation_date date not null
    );
    

    이 갭 날짜 시퀀스에서 연속 된 범위를 추출한다.

    select l.creation_date  as start_d, -- Get first date in contiguous range
        (
            select min(a.creation_date ) as creation_date 
            from "DBA"."visits" a 
                left outer join "DBA"."visits" b on 
                       a.creation_date = dateadd(day, -1, b.creation_date ) and 
                       a.user_id  = b.user_id 
                where b.creation_date  is null and
                      a.creation_date  >= l.creation_date  and
                      a.user_id  = l.user_id 
        ) as end_d -- Get last date in contiguous range
    from  "DBA"."visits" l
        left outer join "DBA"."visits" r on 
            r.creation_date  = dateadd(day, -1, l.creation_date ) and 
            r.user_id  = l.user_id 
        where r.creation_date  is null
    
  20. from https://stackoverflow.com/questions/1176011/sql-to-determine-minimum-sequential-days-of-access by cc-by-sa and MIT license