如何查询另一个table中的上一条记录?

How to query the previous record that is in another table?

我有一个显示如下内容的视图:

查看大众

| ID |     DT     | VAL|
|----|------------|----|
|  1 | 2016-09-01 |  7 |
|  2 | 2016-08-01 |  5 |
|  3 | 2016-07-01 |  8 |

我有一个 table 的历史日期类似:

Table历史记录

| 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 |

我需要的是在我的视图中添加另一列,其布尔值表示 "the immediately previous record exist in history and has a related value greater than zero"。

预期输出如下:

| 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

我尝试了什么

我使用了下面的查询。它适用于小负载,但在生产中性能不佳,因为我的视图非常复杂并且历史 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

你能试试这个查询吗,它 returns 与你的查询结果相同。它的性能应该很好

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

您可以使用带有 'ROW_NUMBER' 的简单 CTE 来避免多个 JOIN

;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

您可以使用 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