如果您能给我任何有关以下SQL Server挑战的最快解决方案的提示,我将不胜感激:
我们假设我的表格中包含DATE
,CLIENT
以及其他列中的几个特征。我需要计算COLUMN_1
和COLUMN_2
但是:
COLUMN_1
使用客户端的当前DATE
特征以及之前DATE
的{{1}}和COLUMN_1
值(递归)参考)DATE
从当前日期开始另外使用COLUMN_2
值(因此我想引用其最终值,而不是实现列逻辑的特定情况)' 如何在SQL Server中最有效地复制此逻辑?
我正在考虑循环遍历DATA和每个DATA,加入以前的DATA,首先计算COLUMN_1,然后计算COLUMN_2(但是如何确保COLUMN_1中的值可以访问COLUMN_1?)
此致 巴特
答案 0 :(得分:2)
如果没有具体的例子,我们将无法告诉您哪种解决方案最有效,特别是当您正在寻找一种您描述为递归的解决方案时。如果可以使用窗口函数,则可能不需要完整的递归解决方案。
在sql server 2012+中,您可以访问lead()
和lag()
,您可以使用它来根据分区和顺序获取列的上一个和下一个值。
select
client
, date
, nextdate = lead(date) over (partition by client order by date)
, prevdate = lag(date) over (partition by client order by date)
, column1 = 'do stuff with lead/lag'
, column2 = 'do stuff with lead/lag'
from t
rextester示例:http://rextester.com/FFHU71709
返回:
+--------+------------+------------+------------+------------------------+------------------------+
| client | date | nextdate | prevdate | column1 | column2 |
+--------+------------+------------+------------+------------------------+------------------------+
| 1 | 2017-01-01 | 2017-01-02 | NULL | do stuff with lead/lag | do stuff with lead/lag |
| 1 | 2017-01-02 | 2017-01-03 | 2017-01-01 | do stuff with lead/lag | do stuff with lead/lag |
| 1 | 2017-01-03 | NULL | 2017-01-02 | do stuff with lead/lag | do stuff with lead/lag |
| 2 | 2017-01-02 | 2017-01-04 | NULL | do stuff with lead/lag | do stuff with lead/lag |
| 2 | 2017-01-04 | 2017-01-06 | 2017-01-02 | do stuff with lead/lag | do stuff with lead/lag |
| 2 | 2017-01-06 | NULL | 2017-01-04 | do stuff with lead/lag | do stuff with lead/lag |
+--------+------------+------------+------------+------------------------+------------------------+
在SQL Server 2012之前模拟超前/滞后的一种方法是使用outer apply()
select
client
, date
, nextdate
, prevdate
, column1 = 'do stuff with lead/lag'
, column2 = 'do stuff with lead/lag'
from t
outer apply (
select top 1 nextdate = i.date
from t i
where i.client = t.client
and i.date > t.date
order by i.date asc
) n
outer apply (
select top 1 prevdate = i.date
from t i
where i.client = t.client
and i.date < t.date
order by i.date desc
) p
rextester演示:http://rextester.com/GGS1299
返回:
+--------+------------+------------+------------+---------------------------------+---------------------------------+
| client | date | nextdate | prevdate | column1 | column2 |
+--------+------------+------------+------------+---------------------------------+---------------------------------+
| 1 | 2017-01-01 | 2017-01-02 | NULL | do stuff with nextdate/prevdate | do stuff with nextdate/prevdate |
| 1 | 2017-01-02 | 2017-01-03 | 2017-01-01 | do stuff with nextdate/prevdate | do stuff with nextdate/prevdate |
| 1 | 2017-01-03 | NULL | 2017-01-02 | do stuff with nextdate/prevdate | do stuff with nextdate/prevdate |
| 2 | 2017-01-02 | 2017-01-04 | NULL | do stuff with nextdate/prevdate | do stuff with nextdate/prevdate |
| 2 | 2017-01-04 | 2017-01-06 | 2017-01-02 | do stuff with nextdate/prevdate | do stuff with nextdate/prevdate |
| 2 | 2017-01-06 | NULL | 2017-01-04 | do stuff with nextdate/prevdate | do stuff with nextdate/prevdate |
+--------+------------+------------+------------+---------------------------------+---------------------------------+
对于绝对需要递归的解决方案,那么您可能需要使用递归cte。
;with cte as (
-- non recursive cte to add `nextdate` for recursive join
select
t.client
, t.date
, nextdate = x.date
from t
outer apply (
select top 1 i.date
from t i
where i.client = t.client
and i.date > t.date
order by i.date asc
) x
)
, r_cte as (
--anchor rows / starting rows
select
client
, date
, nextdate
, prevDate = convert(date, null)
, column1 = convert(varchar(64),null)
, column2 = convert(varchar(64),null)
from cte t
where not exists (
select 1
from cte as i
where i.client = t.client
and i.date < t.date
)
union all
--recursion starts here
select
c.client
, c.date
, c.nextdate
, prevDate = p.date
, column1 = convert(varchar(64),'do recursive stuff with p.column1')
, column2 = convert(varchar(64),'do recursive stuff with p.column2')
from cte c
inner join r_cte p
on c.client = p.client
and c.date = p.nextdate
)
select *
from r_cte
rextester演示:http://rextester.com/LKH38243
返回:
+--------+------------+------------+------------+-----------------------------------+-----------------------------------+
| client | date | nextdate | prevdate | column1 | column2 |
+--------+------------+------------+------------+-----------------------------------+-----------------------------------+
| 1 | 2017-01-01 | 2017-01-02 | NULL | NULL | NULL |
| 2 | 2017-01-02 | 2017-01-04 | NULL | NULL | NULL |
| 2 | 2017-01-04 | 2017-01-06 | 2017-01-02 | do recursive stuff with p.column1 | do recursive stuff with p.column2 |
| 2 | 2017-01-06 | NULL | 2017-01-04 | do recursive stuff with p.column1 | do recursive stuff with p.column2 |
| 1 | 2017-01-02 | 2017-01-03 | 2017-01-01 | do recursive stuff with p.column1 | do recursive stuff with p.column2 |
| 1 | 2017-01-03 | NULL | 2017-01-02 | do recursive stuff with p.column1 | do recursive stuff with p.column2 |
+--------+------------+------------+------------+-----------------------------------+-----------------------------------+
参考
答案 1 :(得分:1)
如果使用SQL2012或更高版本,请查看功能LAG&amp; LEAD
例如,如果你想将前一行的值与此行的值一起使用 - 像这样的LAG:
DECLARE @T TABLE (DateCol DATETIME, StringCol VARCHAR(10))
INSERT INTO @T (DateCol, StringCol) VALUES ('2017-01-01','A'), ('2017-01-02','B'), ('2017-01-03','C'), ('2017-01-04','D'), ('2017-01-05','E')
SELECT DateCol, StringCol, PreviousRowStringcol = LAG(StringCol,1,NULL) OVER (ORDER BY DateCol) FROM @T