不幸的是,我没有创建函数的权限,因此我编写了以下查询,以提取由page_name
分隔的管道的第一,第二,第三和第四部分:
select page_name,
LEFT(page_name, first-1) AS P1,
case when second>0 then SUBSTRING(page_name,first+1,second-first-1)
else substring(page_name, first+1,1000) end As P2,
case when third>0 then SUBSTRING(page_name,second+1,third-second-1)
when second>0 then substring(page_name, second+1,1000) else '' end AS P3,
case when fourth>0 then SUBSTRING(page_name,third+1,fourth-third-1)
when third>0 then substring(page_name, third+1,1000) else '' end AS P4
from (
select distinct page_name,
CHARINDEX('|', page_name) first,
CHARINDEX('|', page_name, CHARINDEX('|', page_name)+1) second,
case when CHARINDEX('|', page_name, CHARINDEX('|', page_name)+1)=0 then 0
else CHARINDEX('|', page_name, CHARINDEX('|', page_name, charindex('|', page_name)+1)+1) end third,
case when CHARINDEX('|', page_name, CHARINDEX('|', page_name, charindex('|', page_name)+1)+1)=0 then 0
else CHARINDEX('|', page_name, CHARINDEX('|', page_name, CHARINDEX('|', page_name, charindex('|', page_name)+1)+1)+1) end fourth
from adobe_analytics
where page_name like '[a-z]%' and page_name like '%|%'
) a
问题是,有时大约有10个部分,所以我想知道是否有更好的子查询编写方法,这不会迫使我在创建{{1}时重申相同类型的查询公式} 部分?
示例数据:
page_name
答案 0 :(得分:1)
如果您事先知道可以有的分隔字符串的最大数量,则可以在以下几行中使用某些内容(它使用递归CTE来构建单独字符串的表,然后旋转它们,产生一行每个page_name
字段):
-- Table variable is just for example purposes.
DECLARE @tbl table (page_name varchar(255))
;
INSERT INTO @tbl
VALUES
('it-bae|')
, ('it-bae|content|advisor in newsletter')
, ('it-bae|content|area products|showcase products fideuram|fideuram fonditalia dynamic')
, ('it-bae|content|events|events|events|webinars|new')
;
WITH cteParts
AS
(
SELECT
page_name
, 1 single_page_no
, CASE WHEN CHARINDEX('|', page_name) = 0 THEN page_name ELSE LEFT(page_name, CHARINDEX('|', page_name) - 1) END single_page_name
, CASE WHEN CHARINDEX('|', page_name) > 0 THEN RIGHT(page_name, LEN(page_name) - CHARINDEX('|', page_name)) END remainder
, ROW_NUMBER() OVER (ORDER BY page_name) row_id
FROM @tbl
UNION ALL
SELECT
page_name
, single_page_no + 1
, CASE WHEN CHARINDEX('|', remainder) > 0 THEN LEFT(remainder, CHARINDEX('|', remainder) - 1) ELSE remainder END
, CASE WHEN CHARINDEX('|', remainder) > 0 THEN RIGHT(remainder, LEN(remainder) - CHARINDEX('|', remainder)) END
, row_id
FROM cteParts
WHERE LEN(remainder) > 0
)
SELECT
row_id
, page_name
, [1]
, [2]
, [3]
, [4]
, [5]
, [6]
, [7]
, [8]
, [9]
, [10]
FROM
(
SELECT
row_id
, page_name
, single_page_no
, single_page_name
FROM cteParts
) Q
PIVOT
(
MAX(single_page_name)
FOR single_page_no IN ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10])
) P
否则,您将需要使用动态SQL来实现类似的目的。
以下是动态SQL解决方案的示例:
-- Temporary table is just for example purposes.
CREATE TABLE #tbl (page_name varchar(255))
;
INSERT INTO #tbl
VALUES
('it-bae|')
, ('it-bae|content|advisor in newsletter')
, ('it-bae|content|area products|showcase products fideuram|fideuram fonditalia dynamic')
, ('it-bae|content|events|events|events|webinars|new')
;
DECLARE @maxStrings int =
(
SELECT MAX(LEN(page_name) - LEN(REPLACE(page_name, '|', ''))) + 1
FROM #tbl
)
;
DECLARE @headers varchar(1000)
;
WITH cteHeaders
AS
(
SELECT 1 Header
UNION ALL
SELECT Header + 1
FROM cteHeaders
WHERE Header + 1 <= @maxStrings
)
SELECT DISTINCT @headers = STUFF((SELECT ', [' + CAST(Header AS varchar(3)) + ']' FROM cteHeaders FOR XML PATH('')), 1, 2, '')
FROM cteHeaders
;
DECLARE @sql varchar(8000) =
'
WITH cteParts
AS
(
SELECT
page_name
, 1 single_page_no
, CASE WHEN CHARINDEX(''|'', page_name) = 0 THEN page_name ELSE LEFT(page_name, CHARINDEX(''|'', page_name) - 1) END single_page_name
, CASE WHEN CHARINDEX(''|'', page_name) > 0 THEN RIGHT(page_name, LEN(page_name) - CHARINDEX(''|'', page_name)) END remainder
, ROW_NUMBER() OVER (ORDER BY page_name) row_id
FROM #tbl
UNION ALL
SELECT
page_name
, single_page_no + 1
, CASE WHEN CHARINDEX(''|'', remainder) > 0 THEN LEFT(remainder, CHARINDEX(''|'', remainder) - 1) ELSE remainder END
, CASE WHEN CHARINDEX(''|'', remainder) > 0 THEN RIGHT(remainder, LEN(remainder) - CHARINDEX(''|'', remainder)) END
, row_id
FROM cteParts
WHERE LEN(remainder) > 0
)
SELECT
row_id
, page_name
, ' + @headers + '
FROM
(
SELECT
row_id
, page_name
, single_page_no
, single_page_name
FROM cteParts
) Q
PIVOT
(
MAX(single_page_name)
FOR single_page_no IN (' + @headers + ')
) P
'
EXEC (@sql)
DROP TABLE #tbl
答案 1 :(得分:1)
我不确定您是否需要列或行中的值。如果值的数量未知,则在行中会更有意义。这可以通过xml拆分器来实现。
SELECT page_name,
Value
FROM @tbl
CROSS APPLY( SELECT cast(('<X>' + replace( page_name, '|' ,'</X><X>') + '</X>') as xml) AS xmlpage_name) AS x
CROSS APPLY( SELECT N.value('.', 'varchar(255)') as value FROM xmlpage_name.nodes('X') as T(N)) AS Split;
如果需要在列中显示值,则可能应具有定义的列数以保留值。
SELECT page_name,
MAX(CASE WHEN ItemNumber = 1 THEN Value ELSE '' END) AS P1,
MAX(CASE WHEN ItemNumber = 2 THEN Value ELSE '' END) AS P2,
MAX(CASE WHEN ItemNumber = 3 THEN Value ELSE '' END) AS P3,
MAX(CASE WHEN ItemNumber = 4 THEN Value ELSE '' END) AS P4,
MAX(CASE WHEN ItemNumber = 5 THEN Value ELSE '' END) AS P5,
MAX(CASE WHEN ItemNumber = 6 THEN Value ELSE '' END) AS P6,
MAX(CASE WHEN ItemNumber = 7 THEN Value ELSE '' END) AS P7,
MAX(CASE WHEN ItemNumber = 8 THEN Value ELSE '' END) AS P8,
MAX(CASE WHEN ItemNumber = 9 THEN Value ELSE '' END) AS P9,
MAX(CASE WHEN ItemNumber = 10 THEN Value ELSE '' END) AS P10
FROM @tbl
CROSS APPLY( SELECT cast(('<X>' + replace( page_name, '|' ,'</X><X>') + '</X>') as xml) AS xmlpage_name) AS x
CROSS APPLY( SELECT N.value('.', 'varchar(255)') as value, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) ItemNumber FROM xmlpage_name.nodes('X') as T(N)) AS Split
GROUP BY page_name;