我在MS SQL Server中有两个表:
dailyt
- 其中包含每日数据:
date val
---------------------
2014-05-22 10
2014-05-21 9.5
2014-05-20 9
2014-05-19 8
2014-05-18 7.5
etc...
和periodt
- 包含不定期的数据:
date val
---------------------
2014-05-21 2
2014-05-18 1
如果dailyt
中有一行,我想通过在periodt
中添加相应的值来调整其值,其中最接近的日期先于或等于dailyt
行的日期。因此,输出看起来像:
addt
date val
---------------------
2014-05-22 12 <- add 2 from 2014-05-21
2014-05-21 11.5 <- add 2 from 2014-05-21
2014-05-20 10 <- add 1 from 2014-05-18
2014-05-19 9 <- add 1 from 2014-05-18
2014-05-18 8.5 <- add 1 from 2014-05-18
我知道这样做的一种方法是加入dailyt
上的periodt
和periodt.date <= dailyt.date
表,然后强加ROW_NUMBER() (PARTITION BY dailyt.date ORDER BY periodt.date DESC)
条件,然后加WHERE
1}}行号上的条件为= 1。
还有另一种方法可以提高效率吗?或者这是非常优化的?
答案 0 :(得分:4)
我认为使用APPLY将是最有效的方式:
SELECT d.Val,
p.Val,
NewVal = d.Val + ISNULL(p.Val, 0)
FROM Dailyt AS d
OUTER APPLY
( SELECT TOP 1 Val
FROM Periodt p
WHERE p.Date <= d.Date
ORDER BY p.Date DESC
) AS p;
<强> Example on SQL Fiddle 强>
答案 1 :(得分:0)
如果行periodt
行相对较少,那么有一个选项可能非常有效。
使用子查询或CTE将periodt
转换为From / To范围表。 (显然,性能取决于这个初始步骤的执行效率,这就是为什么少数periodt
行更可取。)然后加入dailyt
将非常高效。 E.g。
;WITH PIds AS (
SELECT ROW_NUMBER() OVER(ORDER BY PDate) RN, *
FROM @periodt
),
PRange AS (
SELECT f.PDate AS FromDate, t.PDate as ToDate, f.PVal
FROM PIds f
LEFT OUTER JOIN PIds t ON
t.RN = f.RN + 1
)
SELECT d.*, p.PVal
FROM @dailyt d
LEFT OUTER JOIN PRange p ON
d.DDate >= p.FromDate
AND (d.DDate < p.ToDate OR p.ToDate IS NULL)
ORDER BY 1 DESC
如果要尝试查询,以下内容将使用表变量生成示例数据。注意我向dailyt
添加了一行,以演示日期较小的periodt
条目。
DECLARE @dailyt table (
DDate date NOT NULL,
DVal float NOT NULL
)
INSERT INTO @dailyt(DDate, DVal)
SELECT '20140522', 10
UNION ALL SELECT '20140521', 9.5
UNION ALL SELECT '20140520', 9
UNION ALL SELECT '20140519', 8
UNION ALL SELECT '20140518', 7.5
UNION ALL SELECT '20140517', 6.5
DECLARE @periodt table (
PDate date NOT NULL,
PVal int NOT NULL
)
INSERT INTO @periodt
SELECT '20140521', 2
UNION ALL SELECT '20140518', 1