我有一个包含这样的示例数据的表:
ID Key User
-- ---- -----
1 a test
2 ab test
3 abc test
4 abcd test
5 e test1
6 ef test1
7 efg test1
8 efgh test1
9 t test1
10 ty test1
11 tyu test1
12 tyui test1
Run Code Online (Sandbox Code Playgroud)
数据由用户构造的值的顺序"快照"组成.我想为每个用户实例返回最后一行,构建一个不同的最终Key值.注意大多数行Key包含整个前一行Key加上一个额外的字母?我只想要终止这样一个序列的行,并且是每个链中可能的最长值,Keys它们依次包含前一个Key值.
以上示例数据应返回以下内容:
ID Key User
-- ---- -----
4 abcd test
8 efgh test1
12 tyui test1
Run Code Online (Sandbox Code Playgroud)
我该怎么做呢?
如果没有我的问题的答案,我必须做出这些假设:
ID列表示年表,并且总是增加一个,没有间隙.(更新:我做了一个小调整,使得这个工作与来自不同用户的"交错"数据一起工作,并添加了一些交错和一些棘手的数据给我的小提琴.)
所以这是我的解决方案.在SqlFiddle中看到它.值得注意的是,它模拟了LEADSQL Server 2012中没有的分析JOIN.
WITH Info AS (
SELECT
Grp = Row_Number() OVER (PARTITION BY UserName ORDER BY ID, Which) / 2,
*
FROM
dbo.UserEntry U
CROSS JOIN (
SELECT 1 UNION ALL SELECT 2
) X (Which)
)
SELECT
ID = Max(V.ID),
DataKey = Max(V.DataKey),
UserName = Max(V.UserName)
FROM
Info I
OUTER APPLY (SELECT I.* WHERE Which = 2) V
WHERE I.Grp > 0
GROUP BY
I.UserName,
I.Grp
HAVING
Max(I.DataKey) NOT LIKE Min(I.DataKey) + '_';
Run Code Online (Sandbox Code Playgroud)
输入:
INSERT dbo.UserEntry (ID, DataKey, UserName)
VALUES
(1, 'a', 'test'),
(2, 'ab', 'test'),
(3, 'e', 'test1'),
(4, 'ef', 'test1'),
(5, 'abc', 'test'),
(6, 'abcd', 'test'),
(7, 'efg', 'test1'),
(8, 'efgh', 'test1'),
(9, 't', 'test1'),
(10, 'ty', 'test1'),
(11, 'tyu', 'test1'),
(12, 'tyui', 'test1'),
(13, 't', 'test1'),
(14, 'a', 'test'),
(15, 'a', 'test'),
(16, 'ab', 'test'),
(17, 'abc', 'test'),
(18, 'abcd', 'test'),
(19, 'to', 'test1'),
(20, 'abcde', 'test'),
(21, 'top', 'test1');
Run Code Online (Sandbox Code Playgroud)
输出:
ID DataKey UserName
-- ------- --------
6 abcd test
8 efgh test1
12 tyui test1
14 a test
20 abcde test
21 top test1
Run Code Online (Sandbox Code Playgroud)
注意:我使用了不同的列名,因为使用保留字作为列名不是最佳做法(它会强制您在名称周围放置方括号).
我使用的技术将使用单次扫描.它没有连接.使用适当索引的正确构造的基于连接的查询可能在CPU和时间上略胜一筹,但此解决方案肯定会有最少的读取.
更新
虽然我的查询可能很好,但这个问题中的特定数据结构有助于我在第一次回答时没有考虑的非常优雅的解决方案.感谢Andriy的基本想法,这里有一个炸药和超简单的查询(与上面相同的小提琴).
WITH Info AS (
SELECT
Grp = Row_Number() OVER (PARTITION BY UserName ORDER BY ID) - Len(DataKey),
*
FROM
dbo.UserEntry U
)
SELECT
ID = Max(I.ID),
DataKey = Max(I.DataKey),
I.UserName
FROM
Info I
GROUP BY
I.UserName,
I.Grp;
Run Code Online (Sandbox Code Playgroud)
存在 EXISTS 的选项
SELECT *
FROM dbo.test37 t1
WHERE EXISTS (
SELECT *
FROM dbo.test37 t2
WHERE t1.[user] = t2.[user]
GROUP BY LEFT([Key], 1), [User]
HAVING MAX([Key]) = t1.[Key]
)
Run Code Online (Sandbox Code Playgroud)
SQLFiddle上的演示
更新
;WITH cte AS
(
SELECT t1.[Key], t1.[User], ROW_NUMBER() OVER(ORDER BY t1.[User], t1.[Key]) AS Id
FROM dbo.test37 t1
)
SELECT c1.[Key], c1.[User]
FROM cte c1 LEFT JOIN cte c2 ON c1.ID + 1 = c2.Id
WHERE ISNULL(c2.[Key], '') NOT LIKE ISNULL(c1.[Key], '') + '%'
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1655 次 |
| 最近记录: |