我的视图显示如下内容:
| ID | DT | VAL|
|----|------------|----|
| 1 | 2016-09-01 | 7 |
| 2 | 2016-08-01 | 5 |
| 3 | 2016-07-01 | 8 |
我有一张历史日期的表格,如下所示:
| ID | DT | VAL|
|----|------------|----|
| 1 | 2016-06-27 | 4 |
| 1 | 2016-06-29 | 3 |
| 1 | 2016-07-15 | 0 |
| 1 | 2016-09-12 | 8 |
| 2 | 2016-05-05 | 3 |
我需要的是在我的视图中添加另一列,其中包含一个布尔值,表示“历史记录中存在前一条记录并且其相关值大于零”。
预期输出如下:
| ID | DT | VAL| FLAG |
|----|------------|----|------|
| 1 | 2016-09-01 | 7 | false| -- previous is '2016-07-15' and value is zero. '2016-09-12' in hist is greater than '2016-09-01' in view, so it is not the previous
| 2 | 2016-08-01 | 5 | true | -- previous is '2016-05-05' and value is 3
| 3 | 2016-07-01 | 8 | false| -- there is no previous value in HIST table
我使用了以下查询。它适用于小负载,但在生产中性能失败,因为我的视图非常复杂且历史表太大。是否可以在不使用视图的情况下多次查询? (如果是这样,表现应该更好,我不会再看到超时)
您可以在这里测试http://rextester.com/l/sql_server_online_compiler
create table vw (id int, dt date, val int);
insert into vw values (1, '2016-09-01', 7), (2, '2016-08-01', 5), (3, '2016-07-01', 8);
create table hist (id int, dt date, val int);
insert into hist values (1, '2016-06-27', 4), (1, '2016-06-29', 3), (1, '2016-07-15', 0), (1, '2016-09-12', 8), (2, '2016-05-05', 3);
select vw.id, vw.dt, vw.val, (case when hist_with_flag.flag = 'true' then 'true' else 'false' end)
from vw
left join
(
select hist.id, (case when hist.val > 0 then 'true' else 'false' end) flag
from
(
select hist.id, max(hist.dt) as dt
from hist
inner join vw on vw.id = hist.id
where hist.dt < vw.dt
group by hist.id
) hist_with_max_dt
inner join hist
on hist.id = hist_with_max_dt.id and hist.dt = hist_with_max_dt.dt
) hist_with_flag
on vw.id = hist_with_flag.id
答案 0 :(得分:1)
您可以尝试使用此查询,它会返回与查询相同的结果。它应该在性能方面表现良好
SELECT vw.id, MAX(vw.dt) dt,
MAX(vw.val) val,
case when MAX(h.val) > 0 then 'true' else 'false' END flag
FROM vw
OUTER APPLY(SELECT MAX(dt) dt FROM hist WHERE vw.id = hist.id
AND dt<vw.dt GROUP BY hist.id) t
LEFT JOIN hist h ON vw.id = h.id AND h.dt = t.dt
GROUP BY vw.id
答案 1 :(得分:1)
您可以使用带有“ROW_NUMBER”的简单JOIN
来避免多个CTE
。
;with cte_1
as
(select vw.id, vw.dt, vw.val,hist.val HistVal,hist.dt HistDt,ROW_NUMBER()OVER (PARTITION BY vw.id,vw.dt ORDER BY vw.id,vw.dt,hist.dt desc) RNO
FROM vw
left join hist
on hist.id = vw.id and hist.dt < vw.dt
)
SELECT Id,Dt,Val,case when ISNULL(HistVal,0)=0 THEN 'FALSE' ELSE 'TRUE' END as FLAG
FROM cte_1 WHERE RNO=1
答案 2 :(得分:1)
您可以使用OUTER APPLY
来获取之前的记录:
SELECT v.ID, v.DT, v.VAL,
IIF(t.VAL IS NULL OR t.VAL = 0, 'false', 'true') AS FLAG
FROM Vw AS v
OUTER APPLY (
SELECT TOP 1 VAL, DT
FROM Hist AS h
WHERE v.ID = h.ID AND v.DT > h.DT
ORDER BY h.DT DESC) AS t