Sql 使用递归CTE查找父级和子级
我有一个小要求Sql 使用递归CTE查找父级和子级,sql,sql-server-2005,tsql,common-table-expression,Sql,Sql Server 2005,Tsql,Common Table Expression,我有一个小要求 DECLARE @t TABLE (Data VARCHAR(50)) INSERT INTO @t SELECT 'A,B,C' UNION ALL SELECT 'I,J,K' UNION ALL SELECT 'A,D' SELECT DISTINCT b.Item AS Child, CASE WHEN CHARINDEX(b.Item,a.Data)=1 THEN null ELSE SUBSTRING(a.data, 1,CHARINDEX(',',a.dat
DECLARE @t TABLE (Data VARCHAR(50))
INSERT INTO @t SELECT 'A,B,C' UNION ALL SELECT 'I,J,K' UNION ALL SELECT 'A,D'
SELECT DISTINCT b.Item AS Child,
CASE WHEN
CHARINDEX(b.Item,a.Data)=1
THEN null
ELSE SUBSTRING(a.data, 1,CHARINDEX(',',a.data)-1) END AS Parent FROM @t a CROSS APPLY dbo.split(a.Data,',') b
我有一些数据如下
Data
-----
A,B,C
I,J,K
A,D
DDL如下所示
我要做的就是输出
Parent Child
------- -------
Null A
Null I
A B
A C
I J
J K
A D
到目前为止,我的方法仍在进行中,但不起作用
;With cte as (
SSELECT Parent = null, Child = substring(data, 1, CHARINDEX(',',data)-1)
FROM @t
Union all
SELECT t.child, substring(t.data, CHARINDEX(',',t.data)+1, LEN(t.data))
FROM @t t
JOIN cte c ON c.child <> t.child )
Select * from cte
结果:
Parent Child
------ -----
NULL A
NULL I
A B
A D
B C
I J
J K
parent child
-------- -----
NULL A
NULL I
A B
A D
B C
I J
J K
您可以使用下面的select查询来查询需求
DECLARE @t TABLE (Data VARCHAR(50))
INSERT INTO @t SELECT 'A,B,C' UNION ALL SELECT 'I,J,K' UNION ALL SELECT 'A,D'
SELECT DISTINCT b.Item AS Child,
CASE WHEN
CHARINDEX(b.Item,a.Data)=1
THEN null
ELSE SUBSTRING(a.data, 1,CHARINDEX(',',a.data)-1) END AS Parent FROM @t a CROSS APPLY dbo.split(a.Data,',') b
为此,您需要有一个用户定义的Split函数,该函数返回表变量
CREATE FUNCTION [dbo].[Split]
(
@ItemList VARCHAR(4000),
@delimiter VARCHAR(10)
)
RETURNS @IDTable TABLE (ID INT IDENTITY(1,1),Item VARCHAR(500))
AS
BEGIN
-- This function is used to split up multi-value parameters
DECLARE @tempItemList NVARCHAR(4000)
SET @tempItemList = @ItemList
DECLARE @i INT
DECLARE @Item NVARCHAR(4000)
SET @tempItemList = REPLACE (@tempItemList, ' ' + @delimiter, @delimiter)
SET @tempItemList = REPLACE (@tempItemList, @delimiter + ' ', @delimiter)
SET @i = CHARINDEX(@delimiter, @tempItemList)
WHILE (LEN(@tempItemList) > 0)
BEGIN
IF @i = 0
SET @Item = @tempItemList
ELSE
SET @Item = LEFT(@tempItemList, @i -1)
INSERT INTO @IDTable(Item) VALUES(@Item)
IF @i = 0
SET @tempItemList = ''
ELSE
SET @tempItemList = RIGHT(@tempItemList, LEN(@tempItemList) - (@i + LEN(@delimiter)-1))
SET @i = CHARINDEX(@delimiter, @tempItemList)
END
RETURN
END
如果可能的话,我宁愿建议更改所需的表结构,同时考虑性能
希望这是有用的。只想检查一下,这是考虑性能的最佳方式。我已经检查过了,交叉应用和分割功能似乎是一个更好的性能选择。@suryakiran-我还没有对此进行任何性能测试。我不认为像这样拆分字符串是应该经常做的事情。也许只有当您需要通过规范化数据库结构来修复一个糟糕的数据库设计时。我建议在数据库设计中,随着表的增长,这不会产生乐观的输出。我认为我的版本在这里表现最好
DECLARE @t TABLE (Data VARCHAR(50))
INSERT INTO @t SELECT 'A,B,C' UNION ALL SELECT 'I,J,K' UNION ALL SELECT 'A,D'
;WITH cte as (
SELECT
CAST(null AS VARCHAR(50)) Parent,
Child = Left(data, CHARINDEX(',',data)-1),
CAST(Stuff(data, 1, CHARINDEX(',',data), '') + ',' as VARCHAR(50)) Leftover
FROM @t
UNION ALL
SELECT cte.Child,
Left(cte.leftover, CHARINDEX(',',cte.leftover)-1),
CAST(Stuff(cte.leftover, 1, CHARINDEX(',',cte.leftover ), '') as VARCHAR(50))
FROM cte
WHERE cte.leftover <> '')
SELECT DISTINCT parent, child FROM cte
parent child
-------- -----
NULL A
NULL I
A B
A D
B C
I J
J K