2013-04-24 4 views
3

이 파생 테이블을 반환하는 SQL 스크립트가 있습니다. 당신이 볼 수 있듯이조인을 사용하여 누락 된 행 삽입

MM/YYYY Cat Score 
01/2012 Test1 17 
02/2012 Test1 19 
04/2012 Test1 15 
05/2012 Test1 16 
07/2012 Test1 14 
08/2012 Test1 15 
09/2012 Test1 15 
12/2012 Test1 11 
01/2013 Test2 10 
02/2013 Test2 15 
03/2013 Test2 13 
05/2013 Test2 18 
06/2013 Test2 14 
08/2013 Test2 15 
09/2013 Test2 14 
12/2013 Test2 10 

것은 좀 MM/YYYYs을 잃었 (03/2012, 06/2012, 2,012분의 11 등).

고양이 & 점수가 누락 된 MM/YYYY를 채우고 싶습니다.

쿼리가 실행될 범위에 대해 모든 MM/YYYY가 포함 된 테이블을 조인하려고 시도했으나 첫 번째 발생에 대해 누락 된 행만 반환하며 각 Cat에 대해 반복하지 않습니다 (알고 있어야 함) 그).

제 질문은 이것입니다. 조인을 사용하여이 작업을 수행 할 수 있습니까? 아니면 임시 테이블에서이 작업을 수행 한 다음 데이터를 출력해야합니까?

AHIGA, LarryR ...

답변

0

이 하나의 시도 -

DECLARE @temp TABLE (FDOM DATETIME, Cat NVARCHAR(50), Score INT) 

INSERT INTO @temp (FDOM, Cat, Score) 
VALUES 
    ('20120101', 'Test1', 17),('20120201', 'Test1', 19), 
    ('20120401', 'Test1', 15),('20120501', 'Test1', 16), 
    ('20120701', 'Test1', 14),('20120801', 'Test1', 15), 
    ('20120901', 'Test1', 15),('20121001', 'Test1', 13), 
    ('20121201', 'Test1', 11),('20130101', 'Test1', 10), 
    ('20130201', 'Test1', 15),('20130301', 'Test1', 13), 
    ('20130501', 'Test1', 18),('20130601', 'Test1', 14), 
    ('20130801', 'Test1', 15),('20130901', 'Test1', 14), 
    ('20131201', 'Test1', 10),('20120601', 'Test2', 10) 

;WITH enum AS 
(
    SELECT Cat, StartDate = MIN(FDOM), EndDate = MAX(FDOM) 
    FROM @temp 
    GROUP BY Cat 

    UNION ALL 

    SELECT Cat, DATEADD(MONTH, 1, StartDate), EndDate 
    FROM enum 
    WHERE StartDate < EndDate 
) 
SELECT e.StartDate, t.Cat, Score = ISNULL(t.Score, 0) 
FROM enum e 
LEFT JOIN @temp t ON e.StartDate = t.FDOM AND e.Cat = t.Cat 
ORDER BY e.StartDate, t.Cat 
+1

작은 범위에서 성능 차이가 미미할지라도 일반적으로 순차적 CTE를 사용하면 순차적 목록을 생성하는 것이 쉽지 않습니다. [이 기사의 SQL 성능] (http://www.sqlperformance.com/2013/01/t-sql-queries/generate-a-set-2)은 SQL에서 순차적 목록을 생성하는 데 사용할 수있는 다양한 방법에 대한 테스트를 보여줍니다. -섬기는 사람. – GarethD

+0

'('20120601', 'Test2', 10)'과 같이 추가 행이'@ temp' 테이블에 추가되면 결과에서도 test1에 대해 '20120601'이 더 이상 고려되지 않으므로 실패합니다. 2012 년 6 월 시험에 대한 기록이 없다. – GarethD

+0

@ GarthD, 발언 해 주셔서 감사합니다. 그럼에도 불구하고 원래 문제는 과제를 해결하는 것이 었습니다. 어떤 경우 CTE를 사용하는 것이 최적이 아니라는 사실에 관해서 나는 당신의 의견에 동의합니다. 그러나이 특정 작업에 대해 우리는 50,000 개가 넘는 값의 시퀀스를 생성하기 위해 그다지 앞을 내다 보지 않습니다. 이러한 관점에서 쿼리 생산성이 감소하는 것을 보지 못할 수도 있습니다. – Devart

0

당신이 원하는 것을 얻으려면, 드라이버 테이블로 시작하고 left outer join를 사용합니다. 결과는 다음과 같습니다.

select driver.cat, driver.MMYYYY, coalesce(t.score, 0) as score 
from (select cat, MMYYYY 
     from (select distinct cat from t) c cross join 
      themonths -- use where to get a date range 
    ) driver left outer join 
    t 
    on t.cat = driver.cat and t.MMMYYYY = driver.MMYYYY 
7

범위와 모든 범위의 모든 날짜 목록을 교차 가입해야합니다. 더 테이블 구조를 게시되지했기 때문에 나는 약간 구조를 생각해야합니다,하지만 당신은 달력 테이블이 가정은 다음처럼 사용할 수 있습니다 : 당신이 생성 할 수있는 당신이 일정 테이블이없는 경우

SELECT calendar.Date, 
     Category.Cat, 
     Score = ISNULL(Scores.Score, 0) 
FROM Calendar 
     CROSS JOIN Catogory 
     LEFT JOIN Scores 
      ON Scores.Cat = Category.Cat 
      AND Scores.Date = Calendar.Date 
WHERE Calendar.DayOfMonth = 1; 

을 시스템 테이블 Master..spt_values를 사용하여 날짜 목록 : 하드 코딩 된 날짜 '20120101'이 당신의 범위의 첫 번째 날짜입니다

SELECT Date = DATEADD(MONTH, Number, '20120101') 
    FROM Master..spt_values 
    WHERE Type = 'P'; 

. 실제로, 누락 된 행을 삽입해야하는 경우

부칙

단지 빈칸을 채우는 쿼리를하기보다는이를 사용할 수 있습니다

INSERT Scores (Date, Cat, Score) 
SELECT calendar.Date, 
     Category.Cat, 
     Score = 0 
FROM Calendar 
     CROSS JOIN Catogory 
WHERE Calendar.DayOfMonth = 1 
AND  NOT EXISTS 
     ( SELECT 1 
      FROM Scores 
      WHERE Scores.Cat = Category.Cat 
      AND  Scores.Date = Calendar.Date 
     ) 

을, 비록 내 의견 경우에 데이터를 삽입하는 공백을 채우는 쿼리는 시간 낭비입니다.

+0

GarethD, 귀하의 의견을 보내 주셔서 감사합니다. 그러나 이것은 SP에서 반환 된 테이블이며 변경 옵션이 없습니다. 또한 spt_values를 사용하는 것과 마찬가지로 새로운 것이 하나 있습니다. – larryr

+0

완벽한 답변, 감사합니다! – Craig

0

"complete table"에서 "incomplete table"까지 왼쪽 조인을 수행하고 "incomplete"테이블의 날짜 열을 확인하기 위해 where 문을 설정하십시오. 따라서 선택 쿼리에서 누락 된 결과 만 가져옵니다. 그 후, "tablename에 삽입"하기 만하면됩니다.

첫 번째 실행에서는 불완전한 테이블에 아직없는 두 개의 행을 찾습니다. 그래서 그것은 insert into 진술에 의해 삽입 될 것입니다, 2 개의 행은 영향을받습니다. 두 번째 실행에서는 select 문에서 결과에 0 행이 있으므로 아무 일도 발생하지 않습니다.제로 행 :-) 영향을

샘플 : http://sqlfiddle.com/#!2/895fe/6 는 (그냥 select 문을 표시; 문에 삽입 그냥 작품에 참여하는 방법을 참조 할 필요가 없습니다)

Insert Into supportContacts 


Select * FROM 

(

Select 
'01/2012' as DDate, 'Test1' as Cat, 17 as Score 
UNION 
Select 
'02/2012' as DDate, 'Test1' as Cat, 17 as Score 
UNION 
Select 
'03/2012' as DDate, 'Test1' as Cat, 17 as Score 
UNION 
Select 
'04/2012' as DDate, 'Test1' as Cat, 17 as Score 
UNION 
Select 
'05/2012' as DDate, 'Test1' as Cat, 17 as Score 

) CompleteTable 

LEFT JOIN 

(

Select 
'01/2012' as DDate, 'Test1' as Cat, 17 as Score 
UNION 
Select 
'02/2012' as DDate, 'Test1' as Cat, 17 as Score 
UNION 
Select 
'03/2012' as DDate, 'Test1' as Cat, 17 as Score 


) InCompleteTable 

ON CompleteTable.DDate = IncompleteTable.DDate 

WHERE IncompleteTable.DDate is null