如何正确连接以包含多个列?

时间:2013-01-18 08:54:58

标签: sql sql-server-2008 tsql join

我有一个表格,我想加入日历表来制作时间序列,我这样做:

SELECT thedate AS Date
INTO #CALENDAR
FROM
(
    SELECT *
    FROM Sample.dbo.ExplodeDates('20120101','20121231') as d
) X
GO

CREATE INDEX D ON #CALENDAR(Date)
GO

    SELECT Date, A, B, Value
FROM
(
      SELECT StartDate, A, B, Value
      FROM Sample.dbo.Values
) X
RIGHT OUTER JOIN #CALENDAR
    ON Date = StartDate
ORDER BY Date

DROP TABLE #CALENDAR
GO

除非A和B的列包含NULL,否则我会得到类似的结果:

2012-04-06 00:00:00.000 NULL    NULL    NULL
2012-04-07 00:00:00.000 NULL    NULL    NULL
2012-04-08 00:00:00.000 NULL    NULL    NULL
2012-04-09 00:00:00.000 A1  B1  4256
2012-04-10 00:00:00.000 A1  B1  4498

有没有办法可以得到这样的东西:

2012-04-06 00:00:00.000 A1  B1  0
2012-04-07 00:00:00.000 A1  B1  0
2012-04-08 00:00:00.000 A1  B1  0
2012-04-09 00:00:00.000 A1  B1  4256
2012-04-10 00:00:00.000 A1  B1  4498

我给了这个例子一对(A1,B1),但还有其他一些。有关如何实现这一目标的任何建议?

更新

更好的独立示例:

-- The explore dates function

USE Sample
GO

/****** Object:  UserDefinedFunction [dbo].[ExplodeDates]    Script Date: 01/18/2013 01:08:11 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ExplodeDates]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
BEGIN
execute dbo.sp_executesql @statement = N'CREATE FUNCTION [dbo].[ExplodeDates](@startdate datetime, @enddate datetime)
returns table as
return (
with 
 N0 as (SELECT 1 as n UNION ALL SELECT 1)
,N1 as (SELECT 1 as n FROM N0 t1, N0 t2)
,N2 as (SELECT 1 as n FROM N1 t1, N1 t2)
,N3 as (SELECT 1 as n FROM N2 t1, N2 t2)
,N4 as (SELECT 1 as n FROM N3 t1, N3 t2)
,N5 as (SELECT 1 as n FROM N4 t1, N4 t2)
,N6 as (SELECT 1 as n FROM N5 t1, N5 t2)
,nums as (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) as num FROM N6)
SELECT DATEADD(day,num-1,@startdate) as thedate
FROM nums
WHERE num <= DATEDIFF(day,@startdate,@enddate) + 1
);' 
END

GO

SELECT thedate AS Date
INTO #CALENDAR
FROM
(
    SELECT *
    FROM Sample.dbo.ExplodeDates('20120101','20120103') as d
) X
GO

CREATE INDEX D ON #CALENDAR(Date)
GO

CREATE TABLE #TEMP(StartDate datetime, A varchar(50), B varchar(50), Value int)

INSERT INTO #TEMP VALUES('2012-01-01', 'A1', 'A1B1', 10)
INSERT INTO #TEMP VALUES('2012-01-02', 'A1', 'A1B2', 10)
INSERT INTO #TEMP VALUES('2012-01-02', 'A2', 'A2B2', 100)


-- SELECT all traffic values
SELECT Date, A, B, Value
FROM
(
  SELECT StartDate, A, B, Value
  FROM #TEMP
) X
RIGHT OUTER JOIN #CALENDAR
ON Date = StartDate
ORDER BY A, B, Date

DROP TABLE #CALENDAR
DROP TABLE #TEMP
GO

它现在给我的输出:

2012-01-03 00:00:00.000 NULL    NULL    NULL
2012-01-01 00:00:00.000 A1  A1B1    10
2012-01-02 00:00:00.000 A1  A1B2    14
2012-01-02 00:00:00.000 A2  A2B2    100

我想要的输出:

2012-01-01 00:00:00.000 A1  A1B1    0
2012-01-02 00:00:00.000 A1  A1B1    10
2012-01-03 00:00:00.000 A1  A1B1    0
2012-01-01 00:00:00.000 A1  A1B1    10
2012-01-02 00:00:00.000 A1  A1B2    14
2012-01-03 00:00:00.000 A1  A1B2    0
2012-01-01 00:00:00.000 A2  A2B2    0
2012-01-02 00:00:00.000 A2  A2B2    100
2012-01-03 00:00:00.000 A2  A2B2    0

2 个答案:

答案 0 :(得分:1)

要使Value列包含值0而不是NULL,请使用:

SELECT Date, A, B, ISNULL(Value,0)
FROM
(
      SELECT StartDate, A, B, Value
      FROM Sample.dbo.Values
) X
RIGHT OUTER JOIN #CALENDAR
    ON Date = StartDate
ORDER BY Date

同样,您可以使A和B列包含A1和B1,如下所示:

SELECT Date, ISNULL(A,'A1'), ISNULL(B,'B1'), ISNULL(Value,0)
FROM
(
      SELECT StartDate, A, B, Value
      FROM Sample.dbo.Values
) X
RIGHT OUTER JOIN #CALENDAR
    ON Date = StartDate
ORDER BY Date

如果A和B还有其他值,这是否足够好从问题中不清楚。

答案 1 :(得分:1)

select 
    b.date, 
    a.A, 
    a.B, 
    case 
      when a.date = b.date then a.value 
      else 0 
    end as Value
from #temp a 
cross join #calendar b
-- where b.date between -- as calendar filter

不是典型交叉连接的示例 我没有测试,但会在秒中进行:D