我有一个返回此派生表的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 / YYYY(03 / 2012,66 / 2012,11 / 2012等)。
我想用猫与猫填写失踪的MM / YYYY得分为0(零)。
我试图加入一个包含查询将运行范围的所有MM / YYYY的表,但是这只会返回第一次出现的缺失行,而不会为每个Cat重复(应该知道的是)。
所以我的问题是这个,我可以使用连接执行此操作,还是必须在临时表中执行此操作,然后输出数据。
AHIGA, LarryR ...
答案 0 :(得分: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
生成日期列表:
SELECT Date = DATEADD(MONTH, Number, '20120101')
FROM Master..spt_values
WHERE Type = 'P';
硬编码日期'20120101'是您所在范围内的第一个日期。
<强>附录强>
如果你需要实际插入缺失的行,而不是仅仅有一个填充空白的查询,你可以使用它:
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
)
虽然,在我看来,如果你有一个填充空白的查询,插入数据有点浪费时间。
答案 1 :(得分: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
答案 2 :(得分:0)
从“完整表”到“不完整表”进行左连接并设置where语句以检查“不完整”表的日期列。因此,您只会在选择查询中获得缺失的结果。之后,只需在之前设置“insert into tablename”。
在第一次运行中,它会找到两行,这些行尚未包含在不完整的表中。所以它将被insert into
语句插入,受影响的两行。在第二次运行中,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
答案 3 :(得分: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