我有一个带有ActionId列的测试表。该列包含值从1到5的不断增加的随机行,然后再次从1到5的另一个值子集开始。数据可以具有一个或多个这样的子集。
我对包含ActionId值为4或5但每个子集中只有最后一个的行感兴趣。因此,在此示例中,我想返回第7和11行。第7行是因为5是该值下降之前的最后一个值,第11行是因为4是该值再次下降之前的最后一个值。对于最后一个子集,该值无需再次下降。值4或5可能位于最后一行。
我可以用一种程序语言对此进行编程,但是我想不出基于集合的SQL解决方案。
CREATE TABLE test (
id [int] IDENTITY(1,1)
,ActionId INT)
INSERT INTO [test] (ActionId ) VALUES
(1), (2), (3), (3), (4), (4), (5), (3), (3), (3), (4), (1),(2)
select * from test
答案 0 :(得分:0)
如果我猜对了,则需要所有值,其中下一行的值小于当前值。如果我是正确的,则可以出于自身目的使用自我加入。以下脚本将为您提供所需的输出-
DECLARE @test TABLE
(
id [int] IDENTITY(1,1),
Actionid INT
)
INSERT INTO @test (Actionid )
VALUES
(1), (2), (3), (3), (4), (4), (5), (3), (3), (3), (4), (1),(2)
SELECT A.*
FROM @test A LEFT JOIN @test B ON A.id = B.id-1
WHERE B.Actionid < A.Actionid
输出为-
id Actionid
7 5
11 4
如果在不考虑任何条件的情况下也需要最后一行的值,只需使用以下命令更改脚本。这将在输出中包含最后一个值2。
SELECT A.*
FROM @test A LEFT JOIN @test B ON A.id = B.id-1
WHERE B.Actionid < A.Actionid
OR B.Actionid IS NULL
答案 1 :(得分:0)
递归CTE可以在这里为您提供帮助:
-您的样机表
DECLARE @test TABLE
(
id [int] IDENTITY(1,1),
Actionid INT
)
INSERT INTO @test (Actionid )
VALUES (1), (2), (3), (3), (4), (4), (5), (3), (3), (3), (4), (1),(2);
-查询
WITH recCTE AS
(
SELECT id
,Actionid
,1 AS GroupKey
,1 AS GroupStep
FROM @test t WHERE id=1 --the IDENTITY is the sorting key obviously and will start with a 1 in this test case.
UNION ALL
SELECT t.id
,t.Actionid
,CASE WHEN t.Actionid<=r.Actionid THEN r.GroupKey+1 ELSE r.GroupKey END
,CASE WHEN t.Actionid<=r.Actionid THEN 1 ELSE r.GroupStep+1 END
FROM @test t
INNER JOIN recCTE r ON t.id=r.id+1
)
SELECT *
FROM recCTE;
简而言之:
我们从第一行开始,依次遍历集合逐行。我们测试的每一行,如果ActionId
没有增加,并为GroupKey
和GroupStep
设置相应的值。
结果
+----+----------+----------+-----------+
| id | Actionid | GroupKey | GroupStep |
+----+----------+----------+-----------+
| 1 | 1 | 1 | 1 |
+----+----------+----------+-----------+
| 2 | 2 | 1 | 2 |
+----+----------+----------+-----------+
| 3 | 3 | 1 | 3 |
+----+----------+----------+-----------+
| 4 | 3 | 2 | 1 |
+----+----------+----------+-----------+
| 5 | 4 | 2 | 2 |
+----+----------+----------+-----------+
| 6 | 4 | 3 | 1 |
+----+----------+----------+-----------+
| 7 | 5 | 3 | 2 |
+----+----------+----------+-----------+
| 8 | 3 | 4 | 1 |
+----+----------+----------+-----------+
| 9 | 3 | 5 | 1 |
+----+----------+----------+-----------+
| 10 | 3 | 6 | 1 |
+----+----------+----------+-----------+
| 11 | 4 | 6 | 2 |
+----+----------+----------+-----------+
| 12 | 1 | 7 | 1 |
+----+----------+----------+-----------+
| 13 | 2 | 7 | 2 |
+----+----------+----------+-----------+
我们可以通过将最终的SELECT更改为此来进行
SELECT TOP 1 WITH TIES *
FROM recCTE
ORDER BY ROW_NUMBER() OVER(PARTITION BY GroupKey ORDER BY GroupStep DESC);
结果显示每个子集的最后一个条目
+----+----------+----------+-----------+
| id | Actionid | GroupKey | GroupStep |
+----+----------+----------+-----------+
| 3 | 3 | 1 | 3 |
+----+----------+----------+-----------+
| 5 | 4 | 2 | 2 |
+----+----------+----------+-----------+
| 8 | 3 | 4 | 1 |
+----+----------+----------+-----------+
| 9 | 3 | 5 | 1 |
+----+----------+----------+-----------+
| 11 | 4 | 6 | 2 |
+----+----------+----------+-----------+
| 7 | 5 | 3 | 2 |
+----+----------+----------+-----------+
| 13 | 2 | 7 | 2 |
+----+----------+----------+-----------+
您可以过滤到最后一个条目为4或5的子集。在这种情况下,我看到的是第7和11行,还有第5行。可能是因为我没有正确理解逻辑...
答案 2 :(得分:0)
这是我想到的查询:
WITH cte
AS
(SELECT id, Actionid, ROW_NUMBER() OVER (ORDER BY id) rn FROM test)
SELECT
prev.id
,prev.Actionid prevActionId
,cur.Actionid curActionId
FROM cte cur
JOIN cte prev
ON prev.rn = cur.rn - 1
WHERE
prev.Actionid > cur.Actionid
AND prev.Actionid IN (4, 5)
答案 3 :(得分:0)
我想出的解决方案涉及一个简单的相关子查询和一个公用表表达式:
;with cte as
(
select id,
ActionId,
isnull((
select top 1 ActionId
from test as t1
where t0.id < t1.id
order by t1.id
), 0) as nextActionId
from test As t0
)
select id, ActionId
from cte
where actionId IN(4,5)
and actionId > nextActionId
子查询根据id
列的顺序为每一行获取下一个actionId。 isnull
在最后一行-返回0
而不是null
。
然后,您所要做的就是查询操作ID为4或5且大于下一个操作ID的cte。