从一组数据生成每日记录

时间:2014-01-30 19:37:53

标签: sql sql-server tsql

我有以下问题:

SELECT C.DateValue, T.CustomerId, T.Balance
FROM Calendar C
CROSS APPLY (
    SELECT TOP(1) StartDate, CustomerId, Balance
    FROM TestData B
    WHERE B.StartDate <= C.DateValue
    ORDER BY StartDate DESC
) AS T
WHERE C.DateValue BETWEEN '1/1/2014' AND '1/14/2014'
ORDER BY CustomerId, DateValue

这需要一组数据,例如:

CustomerId | StartDate | EndDate | Balance

123 | 1/1/2014 | 1/3/2014 | 2000
123 | 1/3/2014 | 1/10/2014 | 1000
123 | 1/10/2014 | null | 500

并将其转换为:

CustomerId | Date | Balance

123 | 1/1/2014 | 2000
123 | 1/2/2014 | 2000
123 | 1/3/2014 | 1000
123 | 1/4/2014 | 1000
123 | 1/5/2014 | 1000
...

我遇到的问题是它只有在有一个CustomerId时才有效。只要我在列表中添加另一个。我试图找到一种方法来改变这个查询,以支持数据集中任意数量的CustomerIds。我可以通过使用如下查询来完成此任务:

SELECT C.DateValue, T.CustomerId , T.Balance
FROM Calendar C
INNER JOIN TestData T on C.DateValue >= T.DataStartDate
    AND (C.DateValue < T.EndDate OR T.EndDate IS NULL)
WHERE C.DateValue BETWEEN '1/1/2014' AND '1/14/2014'

但是当我将它加入到包含数百万客户的实际表中时,上述查询效率非常低。 如何更改查询或编写查询以实现将数据扩展到每日列表的目标?

示例小提琴: http://www.sqlfiddle.com/#!6/d41d8/14320

2 个答案:

答案 0 :(得分:2)

SQL Fiddle

MS SQL Server 2012架构设置

查询1

SELECT S.CustomerId, S.DateValue, T.Balance
FROM (
SELECT DISTINCT CustomerId, DateValue
FROM TestData, Calendar
WHERE DateValue BETWEEN '1/1/2014' AND '1/14/2014') S
CROSS APPLY (
 SELECT TOP(1) Balance
 FROM TestData B
 WHERE B.StartDate <= S.DateValue AND B.CustomerId = S.CustomerId
 ORDER BY StartDate DESC
) AS T
ORDER BY CustomerId, DateValue

<强> Results

| CUSTOMERID |  DATEVALUE | BALANCE |
|------------|------------|---------|
|        123 | 2014-01-01 |   25000 |
|        123 | 2014-01-02 |   25000 |
|        123 | 2014-01-03 |   25000 |
|        123 | 2014-01-04 |   25000 |
|        123 | 2014-01-05 |   25000 |
|        123 | 2014-01-06 |   25000 |
|        123 | 2014-01-07 |   20000 |
|        123 | 2014-01-08 |   20000 |
|        123 | 2014-01-09 |   10000 |
|        123 | 2014-01-10 |   10000 |
|        123 | 2014-01-11 |   10000 |
|        123 | 2014-01-12 |   10000 |
|        123 | 2014-01-13 |   10000 |
|        123 | 2014-01-14 |   10000 |
|        456 | 2014-01-01 |   25000 |
|        456 | 2014-01-02 |   25000 |
|        456 | 2014-01-03 |   25000 |
|        456 | 2014-01-04 |   25000 |
|        456 | 2014-01-05 |   25000 |
|        456 | 2014-01-06 |   25000 |
|        456 | 2014-01-07 |   20000 |
|        456 | 2014-01-08 |   20000 |
|        456 | 2014-01-09 |   10000 |
|        456 | 2014-01-10 |   10000 |
|        456 | 2014-01-11 |   10000 |
|        456 | 2014-01-12 |   10000 |
|        456 | 2014-01-13 |   10000 |
|        456 | 2014-01-14 |   10000 |

答案 1 :(得分:0)

以下是我最终进行的查询:

SELECT C.DateValue, T.CustomerId, T.Balance
FROM Calendar C
CROSS APPLY (
    SELECT B.CustomerId, B.Balance
    FROM TestData B
    WHERE C.DateValue >= B.StartDate AND (C.DateValue < B.EndDate OR B.EndDate IS NULL)
) AS T
WHERE C.DateValue BETWEEN '1/1/2014' AND '1/14/2014'
ORDER BY CustomerId, DateValue

@BogdanSahlean值得我指出正确的方向。关键是要确保WHERE中的CROSS APPLY条款已正确调整。

SQL小提琴: http://www.sqlfiddle.com/#!6/d41d8/14376