我在这个问题上有点卡住,请需要一些SQL帮助。 iv从需要帮助的人那里得到了一个层次结构表,并将其放入另一个表的实际列中。这是查询表的示例行。除了从此表结果中进行工作之外,我无权进行任何调整:
SELECT ID, Path, Path_Values
FROM TABLE1
输出:
ID | Path | Path_Data_Values
----+---------------------------+----------------------------------
1 | Root | Org
2 | Root / Hemisphere | Org / North Hemisphere
3 | Root / Hemisphere / State | Org / North Hemisphere / Texas
4 | Root / State | Org / Texas
上表可以深入到大约10个级别。无论如何,值得庆幸的是,我知道决赛桌的最大深度,而且我可以访问将结果存储在上面的位置,将其转换为上面的结果以读取路径并为其确定合适的列,然后将值插入到最终表中。
此床头柜的可视示例(所需结果):
ID | Root | Hemisphere | State | Other_1 | Other_2 | Other_3
---+------+----------------------+-------+---------+---------+----------
1 | Org | NULL | NULL | NULL | NULL | NULL
2 | Org | Northern Hemisphere | NULL | NULL | NULL | NULL
3 | Org | Northern Hemisphere | Texas | NULL | NULL | NULL
4 | Org | NULL | Texas | NULL | NULL | NULL
答案 0 :(得分:4)
这可以帮助您实现大部分目标。但是,由于数据的定义在行与行之间会发生变化,因此,如果要动态执行操作,则无法按所需顺序获取数据。 (例如,示例应处于2或3的位置,因为这两个位置都显示?没有数据或查询表的知识,那是不可能的。这是一个动态解决方案,但是,它向您显示了生成的代码如果您想手动编码所有职位,则可以获得您想要的结果。
这也使用了DelimitedSplit8k_LEAD
,因为STRING_SPLIT
没有提供分隔列表中某项的顺序位置;使其在这里无用。
CREATE TABLE dbo.YourTable (ID int,
[Path] varchar(8000),
Path_Data_Values varchar(8000));
INSERT INTO dbo.YourTable(ID, [Path], Path_Data_Values)
VALUES (1,'Root','Org'),
(2,'Root / Hemisphere','Org / North Hemisphere'),
(3,'Root / Hemisphere / State','Org / North Hemisphere / Texas'),
(4,'Root / State','Org / Texas');
GO
DECLARE @SQL nvarchar(MAX);
SET @SQL = N'SELECT YT.ID,' + NCHAR(13) + NCHAR(10) +
STUFF((SELECT N',' + NCHAR(13) + NCHAR(10) +
N' MAX(CASE P.Item WHEN ' + QUOTENAME(P.Item,'''') + N' THEN PDV.Item END) AS ' + QUOTENAME(P.Item)
FROM dbo.YourTable YT
CROSS APPLY (VALUES(REPLACE(YT.[Path],' / ','|')))V([Path])
CROSS APPLY dbo.DelimitedSplit8K_LEAD(V.[Path],'|') P
GROUP BY P.Item
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,3,N'') + NCHAR(13) + NCHAR(10) +
N'FROM dbo.YourTable YT' + NCHAR(13) + NCHAR(10) +
N' CROSS APPLY (VALUES(REPLACE(YT.[Path],'' / '',''|''),REPLACE(YT.Path_Data_Values,'' / '',''|'')))V([Path],Path_Data_Values)' + NCHAR(13) + NCHAR(10) +
N' CROSS APPLY dbo.DelimitedSplit8K_LEAD(V.[Path],''|'') P' + NCHAR(13) + NCHAR(10) +
N' CROSS APPLY(SELECT DS.Item FROM dbo.DelimitedSplit8K_LEAD(V.Path_Data_Values,''|'') DS WHERE P.ItemNumber = DS.ItemNumber) PDV' + NCHAR(13) + NCHAR(10) +
N'GROUP BY YT.ID;';
PRINT @SQL;
EXEC sp_executesql @SQL;
答案 1 :(得分:2)
由于Larnu的示例数据,我得以发布另一种方式来实现此目的。
这种方法是构造一个gulp-string-replace
子句以使用动态SQL进行选择。
values
给定样本数据的-- Get the maximum number of columns
DECLARE @ColumnsCount int =
(SELECT MAX(LEN(Path_Data_Values) - LEN(REPLACE(Path_Data_Values, ' / ', ' ')))
FROM YourTAble
)
DECLARE @Sql nvarchar(max) = 'SELECT * FROM (VALUES' +
STUFF(
(
-- Construct the values clause
SELECT ',(''' + REPLACE(data, ' / ', ''',''') + ''')'
FROM
(
-- use Replicate to add the "missing" values to each line
SELECT Path_Data_Values + REPLICATE(' / ', @ColumnsCount - (LEN(Path_Data_Values) - LEN(REPLACE(Path_Data_Values, ' / ', ' ')))) As data
FROM YourTAble
) x
FOR XML PATH('')
), 1, 1, '')
+ ') V (' +
STUFF(
(
-- Construct the values names
SELECT ',' + REPLACE(Path, ' / ', ',')
FROM YourTAble
WHERE LEN(Path) - LEN(REPLACE(Path, ' / ', ' ')) = @ColumnsCount
FOR XML PATH('')
), 1, 1, '')
+ ')';
-- Whenever using dynamic SQL, Print is your best friend
PRINT @Sql
-- this will print, with the sample data provided, the following SQL statement:
-- SELECT * FROM (VALUES('Org','',''),('Org','North Hemisphere',''),('Org','North Hemisphere','Texas'),('Org','Texas','')) V (Root,Hemisphere,State)
-- unremark once print gets you the desired sql
--EXEC(@Sql)
的结果将是这样:
exec(sql)
如果要使用Root Hemisphere State
Org
Org North Hemisphere
Org North Hemisphere Texas
Org Texas
而不是空字符串,就像在构造的动态SQL中将null
替换为''
一样简单。
请注意,对于2017版或更高版本,您可以使用string_agg
代替我以前使用的null
和stuff
组合来简化此操作。
答案 2 :(得分:0)
是否可以创建一个行号表然后进行数据透视?
例如
with cte_t
as
(
Select * From
(
values(1,'Root','Org'),(2,'Root / Hemisphere','Org / North Hemisphere'),(3,'Root / Hemisphere / State','Org / North Hemisphere / Texas'),(4,'Root / State','Org / Texas')
) as t (ID,ThePath,Path_data_Values)
)
SELECT t1.[Id], [x].[value] as ThePath, x.[rn1], [x2].[value] as Path_data_Values, x2.[rn2] -- t1.ThePath,t1.Path_data_Values
FROM cte_t AS t1
CROSS APPLY (SELECT v1.[value], ROW_NUMBER() OVER (PARTITION BY t1.[Id] ORDER BY t1.[Id]) AS RN1 FROM STRING_SPLIT(t1.ThePath, '/') AS [v1]) AS x
CROSS APPLY (SELECT v2.[value], ROW_NUMBER() OVER (PARTITION BY t1.[Id] ORDER BY t1.[Id]) AS RN2 FROM STRING_SPLIT(t1.Path_data_Values, '/') AS [v2]) AS x2