Sql server 2008 如何编写检查前一行的SQL查询?
我在SQL server中有一个表(已排序),其中包含以下内容:Sql server 2008 如何编写检查前一行的SQL查询?,sql-server-2008,Sql Server 2008,我在SQL server中有一个表(已排序),其中包含以下内容: stringname ========== stringA stringA stringB stringB stringA stringC stringC stringC stringA stringname previous_stringname count ========== =================== ===== stringA NULL 1 stringA stri
stringname
==========
stringA
stringA
stringB
stringB
stringA
stringC
stringC
stringC
stringA
stringname previous_stringname count
========== =================== =====
stringA NULL 1
stringA stringA 1
stringA stringB 1
stringA stringC 1
stringB stringA 1
stringB stringB 1
stringC stringA 1
stringC stringC 2
我想输出以下内容:
stringname
==========
stringA
stringA
stringB
stringB
stringA
stringC
stringC
stringC
stringA
stringname previous_stringname count
========== =================== =====
stringA NULL 1
stringA stringA 1
stringA stringB 1
stringA stringC 1
stringB stringA 1
stringB stringB 1
stringC stringA 1
stringC stringC 2
也就是说,对于原始表中的每个stringname以及该stringname的每个前一个条目,我希望输出它具有每个前一个字符串的次数(第一个条目为NULL)
我将如何为此编写SQL查询
我使用的是SQL Server 2008。下面的内容可以解决问题,但作为回报,我希望您用谷歌搜索“递归”,看看谷歌建议搜索什么:) 澄清:递归是通过在temp表和CTE之间的行-1上连接到行来实现的。此方法依赖于有一个独立的
IDENTITY
列(在本例中为ID
),并使用ROWNUMBER()
来说明ID中可能存在的任何间隙。由于ROW\u NUMBER()
不能用于JOIN
中,我不得不求助于在CTE
的递归部分使用子查询。即使你知道你有连续的ID,我还是建议对这种查询使用ROW\u NUMBER
,这只是为了安全起见,因为间隙会把它搞砸
CREATE TABLE #tmp (id INT IDENTITY(1,1),stringname NVARCHAR(MAX))
INSERT #tmp (stringname)
VALUES
('stringA')
,('stringA')
,('stringB')
,('stringB')
,('stringA')
,('stringC')
,('stringC')
,('stringC')
,('stringA')
;WITH StringNames
AS(
SELECT
ROW_NUMBER() OVER (ORDER BY ID) AS Row --Accounts for gaps in ID
,stringname
,CAST(NULL AS NVARCHAR(MAX)) AS previous_stringname
FROM #tmp
WHERE id = 1
UNION ALL
SELECT t.Row
,t.stringname
,s.stringname AS previous_stringname
FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY ID) AS Row --Accounts for gaps in ID
,stringname
FROM #tmp) AS t
JOIN StringNames AS s ON t.row - 1 = s.row
)
SELECT
DISTINCT
stringname
,previous_stringname
,COUNT(*) AS count
FROM StringNames
GROUP BY
stringname
,previous_stringname
ORDER BY stringname
@威尔,你为什么需要身份栏 数据
CREATE TABLE #table (stringname NVARCHAR(MAX))
INSERT #table (stringname)
VALUES ('stringA')
,('stringA')
,('stringB')
,('stringB')
,('stringA')
,('stringC')
,('stringC')
,('stringC')
,('stringA')
查询
;WITH [cteRowNumbers] AS (
SELECT ROW_NUMBER() OVER (ORDER BY $/0) AS [RowNumber],
[stringname],
CAST(NULL AS NVARCHAR(MAX)) AS [previous_stringname]
FROM #table
)
,[cteStringNames] AS (
SELECT [RowNumber],
[stringname],
[previous_stringname]
FROM (
SELECT TOP 1
[RowNumber],
[stringname],
[previous_stringname]
FROM [cteRowNumbers]
) t
UNION ALL
SELECT t.[RowNumber],
t.[stringname],
s.[stringname] AS [previous_stringname]
FROM [cteRowNumbers] AS t
INNER JOIN [cteStringNames] AS s
ON t.[RowNumber] - 1 = s.[RowNumber]
)
SELECT [stringname],
[previous_stringname],
COUNT(*) AS [count]
FROM [cteStringNames]
GROUP BY stringname, previous_stringname
ORDER BY stringname
递归是不必要的;只需使用:
select b.stringname as stringname, a.stringname as previous_stringname
into #tmp
from (select stringname, row_number() over (order by id /* $/0 */) as row from testing) a
right outer join (select stringname, row_number() over (order by id /* $/0 */) as row from testing) b
on a.row = b.row - 1;
select *, count(*) as [count] from #tmp group by stringname, previous_stringname;
我不确定您是否能够在SQL中轻松地做到这一点。最好是查询数据,让程序处理逻辑。查找ROW_NUMBER()和self joinROW_NUMBER不会有帮助,因为不能按顺序使用常量。表中需要另一个标识符,如
IDENTITY
列,以确保按所需顺序查询stringnames。什么意思是表“已排序”?你的意思是说有一个聚集索引没有显示给我们,而这些行是按聚集索引键顺序排列的吗?我以前从未见过这种技巧,这对我来说是个新技巧:)在这种情况下,那么就不需要标识列了。当然,无论使用一个或两个CTE来获得结果,这都会成为一种设计偏好。