替换游标以将表与时间段组合在一起

时间:2014-01-15 20:57:08

标签: sql sql-server tsql

我必须将两个表合并为一个,但我必须将验证日期纳入考虑范围。例如有两个表:

Address
ID          AddressValue    ValidFrom               ValidTo
----------- --------------- ----------------------- -----------------------
1           Pink Street     2010-01-01 00:00:00.000 2010-01-20 00:00:00.000
2           Yellow Street   2010-01-20 00:00:00.000 2010-02-28 00:00:00.000

Phone
ID          PhoneValue   ValidFrom               ValidTo
----------- ------------ ----------------------- -----------------------
1           123456789    2010-01-01 00:00:00.000 2010-01-15 00:00:00.000
2           987654321    2010-01-16 00:00:00.000 2010-01-31 00:00:00.000

我需要将它们组合成新的:

NewSystem
ID          NewPhone    NewAddress      ValidFrom               ValidTo                 Version
----------- ----------- --------------- ----------------------- ----------------------- -------
1           123456789   Pink Street     2010-01-01 00:00:00.000 2010-01-15 00:00:00.000 4
2           NULL        Pink Street     2010-01-15 00:00:00.000 2010-01-16 00:00:00.000 3
3           987654321   Pink Street     2010-01-16 00:00:00.000 2010-01-20 00:00:00.000 2
4           987654321   Yellow Street   2010-01-20 00:00:00.000 2010-01-31 00:00:00.000 1
5           NULL        Yellow Street   2010-01-31 00:00:00.000 2010-02-28 00:00:00.000 0

这个想法非常简单。我根据日期创建句点,然后查询子查询中的每个表。我在此处粘贴了我的解决方案:http://pastebin.com/cdKePA9X

现在我正试图摆脱光标,但我失败了。我试图使用CTE但没有成功。也许有人遇到类似的问题,或者知道如何在不使用游标的情况下将这些表组合成一个。我在这里粘贴了“创建表”脚本:http://pastebin.com/BeRspb6K

先谢谢你。

1 个答案:

答案 0 :(得分:1)

首先,通过合并源表中的日期范围来构造新的日期范围。其次,对于每个新的日期范围,查找源表中的有效数据。

WITH
  old_ranges(d1,d2) AS (
     SELECT ValidFrom,ValidTo FROM @Address UNION
     SELECT ValidFrom,ValidTo FROM @Phone   
  ),
  new_ranges(d1,d2) AS (
    SELECT d,LEAD(d) OVER(ORDER BY d)
    FROM (
      SELECT DISTINCT d
      FROM old_ranges 
      UNPIVOT(d FOR dx IN (d1,d2)) p
    ) t
  )
SELECT
  ROW_NUMBER() OVER (ORDER BY d1) AS ID,
  NewPhone,
  NewAddress,
  d1 AS ValidFrom,
  d2 AS ValidTo
FROM new_ranges
OUTER APPLY (
  SELECT PhoneValue AS NewPhone
  FROM @Phone
  WHERE ValidFrom <= d1 AND ValidTo >= d2
) x1
OUTER APPLY (
  SELECT AddressValue AS NewAddress
  FROM @Address
  WHERE ValidFrom <= d1 AND ValidTo >= d2
) x2
WHERE d2 IS NOT NULL