如果不存在则加入行

时间:2014-04-10 18:34:19

标签: sql sql-server join

我有一个包含按年和周的数据的表格。我想从该表中选择年份和月份子集中的所有内容,以及在找不到该周/年组合的地方使用默认值的行。

这是一个测试脚本:

--create test table and insert data
CREATE TABLE [dbo].[TestPD](
    [id] [int] NOT NULL,
    [year] [int] NOT NULL,
    [week] [int] NOT NULL,
    [name] [varchar](50) NOT NULL,
    [item] [int] NOT NULL,
) ON [PRIMARY]

GO
INSERT [dbo].[TestPD] ([id], [year], [week], [name], [item]) VALUES (1, 2013, 15, N'bob', 5)
INSERT [dbo].[TestPD] ([id], [year], [week], [name], [item]) VALUES (1, 2014, 15, N'bob', 4)
INSERT [dbo].[TestPD] ([id], [year], [week], [name], [item]) VALUES (2, 2013, 15, N'joe', 3)
INSERT [dbo].[TestPD] ([id], [year], [week], [name], [item]) VALUES (3, 2014, 15, N'rick', 2)
INSERT [dbo].[TestPD] ([id], [year], [week], [name], [item]) VALUES (1, 2012, 15, N'rick', 1)
GO

--LookupDates contains the year/week combos to extract from the table
WITH LookupDates AS (
    SELECT DATEPART(YEAR, GETDATE()) AS [LookupYear], DATEPART(WEEK, GETDATE()) as [LookupWeek]
    UNION 
    SELECT DATEPART(YEAR, GETDATE()) - 1, DATEPART(WEEK, GETDATE())
)
--what I tried (doesn't return "blank" rows)
SELECT t1.[LookupYear], t1.[LookupWeek], ISNULL(id, 0), ISNULL(Name, 'not found'), ISNULL(item, 0)
FROM LookupDates as t1 LEFT JOIN TESTPD as t2 on t1.LookupYear = t2.[year] and t1.LookupWeek = t2.[Week]

我喜欢的是看起来像这样的数据(每个id /年/月的一行)组合,无论它是否存在于TestPD表中:(具有0值的行) item实际上并不存在,只是添加了默认值。

id          year        week        name      item
----------- ----------- ----------- --------- -----------
1           2013        1           bob       5
1           2014        1           bob       4
2           2013        1           joe       3
2           2014        1           joe       0
3           2013        1           rick      0
3           2014        1           rick      2

我怎样才能做到这一点?我不必使用CTE,我只是认为这是保存我需要数据的年/周的最佳方式。

2 个答案:

答案 0 :(得分:1)

以下评论编辑。

您需要与ID交叉加入才能获得所需内容。这是一种方法,但这是他们的关键。

--create test table and insert data
CREATE TABLE [dbo].[TestPD](
    [id] [int] NOT NULL,
    [year] [int] NOT NULL,
    [week] [int] NOT NULL,
    [name] [varchar](50) NOT NULL,
    [item] [int] NOT NULL,
) ON [PRIMARY]

GO
INSERT [dbo].[TestPD] ([id], [year], [week], [name], [item]) VALUES (1, 2013, 15, N'bob', 5)
INSERT [dbo].[TestPD] ([id], [year], [week], [name], [item]) VALUES (1, 2014, 15, N'bob', 4)
INSERT [dbo].[TestPD] ([id], [year], [week], [name], [item]) VALUES (2, 2013, 15, N'joe', 3)
INSERT [dbo].[TestPD] ([id], [year], [week], [name], [item]) VALUES (3, 2014, 15, N'rick', 2)
INSERT [dbo].[TestPD] ([id], [year], [week], [name], [item]) VALUES (1, 2012, 15, N'rick', 1)
GO

--LookupDates contains the year/week combos to extract from the table
;WITH LookupDates AS (
    SELECT DATEPART(YEAR, GETDATE()) AS [LookupYear], DATEPART(WEEK, GETDATE()) as [LookupWeek]
    UNION 
    SELECT DATEPART(YEAR, GETDATE()) - 1, DATEPART(WEEK, GETDATE())
)
,UserDates AS (
    SELECT  *
      FROM LookupDates
           CROSS JOIN
           (SELECT id FROM TESTPD GROUP BY id) a
)
SELECT t1.LookupYear
     , t1.LookupWeek
     , ISNULL(t2.id, 0) id
     , ISNULL(Name, 'not found') Name
     , ISNULL(item, 0) Item
FROM UserDates as t1 
     LEFT JOIN 
     TESTPD as t2 on t1.LookupYear = t2.[year] 
                 and t1.LookupWeek = t2.[Week]
                 and t1.id = t2.id



LookupYear  LookupWeek  id          Name                                               Item
----------- ----------- ----------- -------------------------------------------------- -----------
2013        15          1           bob                                                5
2013        15          2           joe                                                3
2013        15          0           not found                                          0
2014        15          1           bob                                                4
2014        15          0           not found                                          0
2014        15          3           rick                                               2

答案 1 :(得分:0)

WITH LookupDates AS (
    SELECT DATEPART(YEAR, GETDATE()) AS [LookupYear], DATEPART(WEEK, GETDATE()) as [LookupWeek]
    UNION 
    SELECT DATEPART(YEAR, GETDATE()) - 1, DATEPART(WEEK, GETDATE())
)

--this will return "blank" rows
SELECT t1.[LookupYear], t1.[LookupWeek], id, Name, item
FROM LookupDates as t1 
JOIN TESTPD as t2 on t1.LookupYear = t2.[year] and t1.LookupWeek = t2.[Week]

UNION ALL

SELECT t1.[LookupYear], t1.[LookupWeek], id, 'Not Found', item
FROM LookupDates AS t1 
CROSS JOIN TESTPD AS t2
WHERE NOT EXISTS (SELECT 1
FROM TESTPD t3
WHERE t3.ID = T2.ID
AND t3.item = T2.item
AND t3.[year] = t1.[LookupYear] 
and t3.[Week] = t1.[LookupWeek])
ORDER BY 1, 2, 3, 4