복붙노트

[SQL] 실종 날짜를 표시하는 SQL 서버

SQL

실종 날짜를 표시하는 SQL 서버

SiteVisitID     siteName        visitDate
------------------------------------------------------    
   1            site1           01/03/2014
   2            Site2           01/03/2014
   3            site1           02/03/2014
   4            site1           03/03/2014
   5            site2           03/03/2014
   6            site1           04/03/2014
   7            site2           04/03/2014
   8            site2           05/03/2014
   9            site1           06/03/2014
  10            site2           06/03/2014
  11            site1           08/03/2014
  12            site2           08/03/2014
  13            site1           09/03/2014
  14            site2           10/03/2014

이 개 사이트와 달의 일상에 대한 방문 항목이 각각 필요가 그래서 오늘 우리는 22 개 항목을 기대하고 2014년 11월 3일 것을 고려하고있다하지만 8 누락, SQL 우리의 모든 방법이 때문에 단지 14 항목이 있습니다 날짜 누락 된 항목을 꺼내 수

사이트에 대한 해당 월의 현재 날짜까지

siteName    missingDate
-----------------------    
site2       02/03/2014
site1       05/03/2014
site1       07/03/2014
site2       07/03/2014
site2       09/03/2014
site1       10/03/2014
site1       11/03/2014
site2       11/03/2014

여기에 내가 믿는 내 실패한 시도가 모두 논리적 구문이 잘못이다

select 
    siteName, visitDate  
from  
    SiteVisit not in (SELECT siteName, visitDate
                      FROM SiteVisit 
                      WHERE Day(visitDate) != Day(CURRENT_TIMESTAMP) 
                        AND Month(visitDate) = Month(CURRENT_TIMESTAMP))

참고 : 실제 테이블의 상기 데이터 열을 간략화 버전

해결법

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

    1.난 당신이 테이블 (이 바이올린에 그것을 밖으로 시도)로 당신이 선택한 날짜 사이의 모든 일을 얻을 수있는 테이블 반환 함수를 사용하는 것이 좋습니다 것입니다 :

    난 당신이 테이블 (이 바이올린에 그것을 밖으로 시도)로 당신이 선택한 날짜 사이의 모든 일을 얻을 수있는 테이블 반환 함수를 사용하는 것이 좋습니다 것입니다 :

    CREATE FUNCTION dbo.GetAllDaysInBetween(@FirstDay DATETIME, @LastDay DATETIME)
    RETURNS @retDays TABLE 
    (
        DayInBetween DATETIME
    )
    AS 
    BEGIN
        DECLARE @currentDay DATETIME
        SELECT @currentDay = @FirstDay
    
        WHILE @currentDay <= @LastDay
        BEGIN
    
            INSERT @retDays (DayInBetween)
                SELECT @currentDay
    
            SELECT @currentDay = DATEADD(DAY, 1, @currentDay)
        END 
    
        RETURN
    END
    

    (I 쉽게 CopyPaste에-시험에 대한 간단한 테이블 설정 포함)

    CREATE TABLE SiteVisit (ID INT PRIMARY KEY IDENTITY(1,1), visitDate DATETIME, visitSite NVARCHAR(512))
    
    INSERT INTO SiteVisit (visitDate, visitSite)
        SELECT '2014-03-11', 'site1'
        UNION
        SELECT '2014-03-12', 'site1'
        UNION
        SELECT '2014-03-15', 'site1'
        UNION
        SELECT '2014-03-18', 'site1'
        UNION
        SELECT '2014-03-18', 'site2'
    

    당신이 이와 같은 "경계 일"알고있을 때 지금 당신은 단순히 어떤 방문이 발생하지 무슨 일 확인하실 수 있습니다 :

    SELECT
            DayInBetween AS missingDate,
            'site1' AS visitSite
        FROM dbo.GetAllDaysInBetween('2014-03-11', '2014-03-18') AS AllDaysInBetween
        WHERE NOT EXISTS 
            (SELECT ID FROM SiteVisit WHERE visitDate = AllDaysInBetween.DayInBetween AND visitSite = 'site1')
    

    아니면 모든 사이트에서이 쿼리를 사용할 수 있습니다 방문하지 않은 모든 일을 알고 싶은 경우 :

    SELECT
            DayInBetween AS missingDate,
            Sites.visitSite
        FROM dbo.GetAllDaysInBetween('2014-03-11', '2014-03-18') AS AllDaysInBetween
        CROSS JOIN (SELECT DISTINCT visitSite FROM SiteVisit) AS Sites
        WHERE NOT EXISTS
            (SELECT ID FROM SiteVisit WHERE visitDate = AllDaysInBetween.DayInBetween AND visitSite = Sites.visitSite)
        ORDER BY visitSite
    

    그냥 보조 노트에 : 당신이 사이트 이름 정말 별도의 테이블로 가야 만 SiteVisit에서 참조 할 테이블 (정규화되지 않음)에 일부 중복이 보인다

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

    2.어쩌면 당신은 시작 지점으로 사용할 수 있습니다 :

    어쩌면 당신은 시작 지점으로 사용할 수 있습니다 :

    -- Recursive CTE to generate a list of dates for the month
    -- You'll probably want to play with making this dynamic
    WITH Dates AS
    (
        SELECT 
            CAST('2014-03-01' AS datetime) visitDate
        UNION ALL
        SELECT 
            visitDate + 1
        FROM 
            Dates
        WHERE
            visitDate + 1 < '2014-04-01'
    )
    -- Build a list of siteNames with each possible date in the month
    , SiteDates AS 
    (
        SELECT 
            s.siteName, d.visitDate 
        FROM 
            SiteVisitEntry s
        CROSS APPLY 
            Dates d
        GROUP BY 
            s.siteName, d.visitDate
    )
    -- Use a left anti-semi join to find the missing dates
    SELECT
        d.siteName, d.visitDate AS missingDate
    FROM
        SiteDates d
    LEFT JOIN
        SiteVisitEntry e /* Plug your actual table name here */
        ON
        d.visitDate = e.visitDate
        AND
        d.siteName = e.siteName
    WHERE
        e.visitDate IS NULL
    OPTION 
        (MAXRECURSION 0)
    
  3. ==============================

    3.당신이 '달력 테이블'을 가지고있을 때 훨씬 간단해진다. 즉, 당신에게 가능한 관심의 모든 날짜를 유지하는 테이블입니다.

    당신이 '달력 테이블'을 가지고있을 때 훨씬 간단해진다. 즉, 당신에게 가능한 관심의 모든 날짜를 유지하는 테이블입니다.

    그 이유는 SQL이없는 무엇에보고 할 수 있다는 것입니다. 그런 다음, (예를 들면 다른 대답을 여기에서와 같이) 간격에 속해야 날짜를 만들 만든 날짜에보고하도록 SQL을 작성할 수 있습니다. 또는 당신은이 '달력 테이블을'지속에 그냥이 그냥 훨씬 더 빨리, 더 자주 다음 SQL 간단하지 만들고, 그것을 사용할 수 있습니다.

    유사한 헛된에서, 당신이 방문을 가질 수있는 모든 사이트를 포함하는 차원 테이블이 있다고 가정? 그렇다면, 당신은 이런 식으로 뭔가를 얻을 수 ...

    SELECT
      *
    FROM
      site
    CROSS JOIN
      calendar
    LEFT JOIN
      visit
        ON  visit.site_id   = site.id
        AND visit.visitDate = calendar.date
    WHERE
          calendar.date   >= DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0) 
      AND calendar.date   <                                    GETDATE()
      AND visit.visitDate IS NULL
    
  4. ==============================

    4.여기에는 사용자 정의 함수 genrate을 구현하고있다.

    여기에는 사용자 정의 함수 genrate을 구현하고있다.

    CREATE FUNCTION genrate(@FROM_date date,@to_date date) 
    RETURNS @tab table(missing date) 
    AS 
    BEGIN 
        ;WITH cte AS
          ( 
            SELECT @FROM_date missing
            UNION ALL 
            SELECT DATEADD(DAY,1,missing)
            FROM cte
            WHERE missing <@to_date 
          )
    
        INSERT INTO @tab
        SELECT *
        FROM cte
        WHERE missing NOT IN (@FROM_date, @to_date) 
        RETURN 
    END
    

    날짜 세트와 함께 실종 생성하는 데이터와 기능은 우리가 십자가를 할 건데 설정 적용을 사용.

    SELECT user_No,
         product_name,
         amount,
         b.missing AS Missing_date
    FROM date_tab t 
    CROSS APPLY DBO.genrate(T.ORDER_DATE,T.DELIVERY) b
    
  5. from https://stackoverflow.com/questions/22329722/sql-server-displaying-missing-dates by cc-by-sa and MIT license