SQL-选择列值更改前后带有日期的行
我有一张表叫test。 在测试中,我有一个ID、一个值和一个日期。 为每个ID排序日期。 我想在值更改前后为ID选择行,因此下面的示例表如下所示 RowNum---ID---Value---Date 1---------001 -----1------ 01/01/2015 2---------001 -----1------ 02/01/2015 3---------001 -----1------ 04/01/2015 4---------001 -----1------ 05/01/2015 5---------001 -----1------ 06/01/2015 6---------001 -----1------ 08/01/2015 7---------001 -----0------ 09/01/2015 8---------001 -----0------ 10/01/2015 9---------001 -----0------ 11/01/2015 10---------001 -----1------ 12/01/2015 11---------001 -----1------ 14/01/2015 12---------002 -----1------ 01/01/2015 13---------002 -----1------ 04/01/2015 14---------002 -----0------ 05/01/2015 15-----------002-------0-------2015年1月7日SQL-选择列值更改前后带有日期的行,sql,sql-server,Sql,Sql Server,我有一张表叫test。 在测试中,我有一个ID、一个值和一个日期。 为每个ID排序日期。 我想在值更改前后为ID选择行,因此下面的示例表如下所示 RowNum---ID---Value---Date 1---------001 -----1------ 01/01/2015 2---------001 -----1------ 02/01/2015 3---------001 -----1------ 04/01/2015 4---------001 -----1------ 05/01/201
结果将返回第6行、第7行、第9行、第10行、第13行、第14行。您可以使用分析函数LAG和LEAD来访问前一行和后一行中的值,然后检查它是否与当前行中的值不匹配
SELECT *
FROM (
SELECT RowNum,
ID,
Value,
Date,
LAG(VALUE, 1, VALUE) OVER(ORDER BY RowNum) PrevValue,
LEAD(VALUE, 1, VALUE) OVER(ORDER BY RowNum) NextValue
FROM test)
WHERE PrevValue <> Value
OR NextValue <> Value
传递给此函数的参数为
本例中的一些标量表达式列名;
前后偏移1行;
默认值LAG将为第一行返回NULL,LEAD将为最后一行返回NULL,但在您的问题中它们似乎并不特别,所以我使用列值作为默认值。
您可以使用分析函数LAG和LEAD访问前面和后面行中的值,然后检查它是否与当前行中的值不匹配
SELECT *
FROM (
SELECT RowNum,
ID,
Value,
Date,
LAG(VALUE, 1, VALUE) OVER(ORDER BY RowNum) PrevValue,
LEAD(VALUE, 1, VALUE) OVER(ORDER BY RowNum) NextValue
FROM test)
WHERE PrevValue <> Value
OR NextValue <> Value
传递给此函数的参数为
本例中的一些标量表达式列名;
前后偏移1行;
默认值LAG将为第一行返回NULL,LEAD将为最后一行返回NULL,但在您的问题中它们似乎并不特别,所以我使用列值作为默认值。
在不使用超前和滞后的情况下,参考以下一项:
DECLARE @i INT = 1,
@cnt INT,
@dstvalue INT,
@srcvalue INT
CREATE TABLE #result
(
id INT,
mydate DATE
)
CREATE TABLE #temp1
(
rn INT IDENTITY(1, 1),
id INT,
mydate DATE
)
INSERT INTO #temp1
(id,
mydate)
SELECT id,
mydate
FROM table
ORDER BY id,
mydate
SELECT @cnt = Count(*)
FROM #temp1
SELECT @srcvalue = value
FROM #temp1
WHERE rn = @i
WHILE ( @i <= @cnt )
BEGIN
SELECT @dstvalue = value
FROM #temp1
WHERE rn = @i
IF( @srcvalue = @dstvalue )
BEGIN
SET @i = @i + 1
CONTINUE;
END
ELSE
BEGIN
SET @srcvalue = @dstvalue
INSERT INTO #result
(id,
mydate)
SELECT id,
mydate
FROM #temp
WHERE rn = @i - 1
UNION ALL
SELECT id,
mydate
FROM #temp
WHERE rn = @i
END
SET @i = @i + 1
END
SELECT *
FROM #result
在不使用超前和滞后的情况下,参考以下一项:
DECLARE @i INT = 1,
@cnt INT,
@dstvalue INT,
@srcvalue INT
CREATE TABLE #result
(
id INT,
mydate DATE
)
CREATE TABLE #temp1
(
rn INT IDENTITY(1, 1),
id INT,
mydate DATE
)
INSERT INTO #temp1
(id,
mydate)
SELECT id,
mydate
FROM table
ORDER BY id,
mydate
SELECT @cnt = Count(*)
FROM #temp1
SELECT @srcvalue = value
FROM #temp1
WHERE rn = @i
WHILE ( @i <= @cnt )
BEGIN
SELECT @dstvalue = value
FROM #temp1
WHERE rn = @i
IF( @srcvalue = @dstvalue )
BEGIN
SET @i = @i + 1
CONTINUE;
END
ELSE
BEGIN
SET @srcvalue = @dstvalue
INSERT INTO #result
(id,
mydate)
SELECT id,
mydate
FROM #temp
WHERE rn = @i - 1
UNION ALL
SELECT id,
mydate
FROM #temp
WHERE rn = @i
END
SET @i = @i + 1
END
SELECT *
FROM #result
使用滞后和超前的答案是正确的答案。如果您使用的是SQL Server 2012之前的版本,则可以使用交叉应用或相关子查询执行基本相同的操作:
select t.*
from test t cross apply
(select top 1 tprev.*
from test tprev
where tprev.date < t.date
order by date desc
) tprev cross apply
(select top 1 tnext.*
from test tnext
where tnext.date > t.date
order by date asc
) tnext
where tprev.value <> tnext.value;
使用滞后和超前的答案是正确的答案。如果您使用的是SQL Server 2012之前的版本,则可以使用交叉应用或相关子查询执行基本相同的操作:
select t.*
from test t cross apply
(select top 1 tprev.*
from test tprev
where tprev.date < t.date
order by date desc
) tprev cross apply
(select top 1 tnext.*
from test tnext
where tnext.date > t.date
order by date asc
) tnext
where tprev.value <> tnext.value;
我可以知道SQL Server的版本吗?解决方案会有所不同我可以知道SQL Server的版本吗?解决方案会有相应的不同