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/YYYY(03/2012、06/2012、11/2012 等)。

我想用 Cat 和 0(零)填写缺少的 MM/YYYYs 分数。

我试图加入一个表,其中包含将运行查询的范围的所有 MM/YYYY,但这只会返回第一次出现的缺失行,它不会为每个 Cat 重复(应该知道这一点)。

所以我的问题是,我可以使用连接来执行此操作,还是必须在临时表中执行此操作,然后输出数据。

AHIGA、LarryR……</p>

4

4 回答 4

8

您需要交叉加入您的类别和范围内所有日期的列表。由于您没有发布任何表格结构,我将不得不稍微猜测您的结构,但假设您有一个日历表,您可以使用如下内容:

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
        )

虽然,在我看来,如果您有一个查询来填补插入数据的空白,这有点浪费时间。

于 2013-04-24T21:58:48.977 回答
1

要获得您想要的,请从驱动程序表开始,然后使用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
于 2013-04-24T21:58:38.320 回答
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
于 2013-04-25T07:02:08.837 回答
0

从“完整表”到“不完整表”进行左连接,并设置 where 语句来检查“不完整”表的日期列。因此,您只会在选择查询中获得缺失的结果。之后,只需在之前设置一个“插入表名”。

在第一次运行中,它将找到两行,它们尚未在不完整的表中。所以它会被insert into语句插入,影响两行。在第二次运行中,select 语句中的结果有 0 行,所以什么也没有发生。零行受影响:-)

示例:http ://sqlfiddle.com/#!2/895fe /6 (只需标记 select 语句;insert into 语句不需要只是查看,join 是如何工作的)

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
于 2013-04-24T22:02:13.063 回答