如何在multivalued
列中查询特定键?
样本数据
ID DAY PRICE
1 01;02;03;04;... 100;230;110;34.5;...
2 01;02;03;04;... 120;240;510;34.5;...
例如:
选择...,其中DAY键='02'
预期:
ID DAY PRICE
1 02 230
2 02 240
注释
实际表有30多个字段。
加入多个CROSS APPLY SPLIT_STRING
看起来很乏味
答案 0 :(得分:2)
这里是一个选项,它将动态地取消透视数据(实际上并没有使用动态SQL),然后透视结果。
您只需要在for Item in (...)
部分列出30列
交叉应用B 会将 ROW 转换为XML
交叉应用C 将 UNPIVOT XML
交叉应用D 将从C中解析/分割定界字符串(带有序列)
那对PIVOT来说就不大了
示例
Declare @YourTable Table ([ID] varchar(50),[DAY] varchar(50),[PRICE] varchar(50))
Insert Into @YourTable Values
(1,'01;02;03;04','100;230;110;34.5')
,(2,'01;02;03;04','120;240;510;34.5')
Select *
From (
Select A.ID
,C.Item
,D.*
From @YOurTable A
Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
Cross Apply (
Select Item = xAttr.value('local-name(.)', 'varchar(100)')
,Value = xAttr.value('.','varchar(max)')
From XMLData.nodes('//@*') xNode(xAttr)
Where xAttr.value('local-name(.)','varchar(100)') not in ('Id','Other-Columns','To-Exclude')
) C
Cross Apply (
Select RetSeq = row_number() over (order by (Select null))
,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(100)')))
From ( values (cast('<x>' + replace(C.Value,';','</x><x>')+'</x>' as xml))) as A(x)
Cross Apply x.nodes('x') AS B(i)
) D
) src
Pivot (max(RetVal) for Item in ([Day],[Price]) ) pvt
Where Day='02'
返回
ID RetSeq Day Price
1 2 02 230
2 2 02 240
答案 1 :(得分:2)
此解决方案使用cte,希望它对您有用:
with cte1 as
(
select id, value daykey,
row_number() over(order by (select null)) as rowid
from mvct
cross apply string_split(day, ";")
),
cte2 as
(
select id, value pricekey,
row_number() over(order by (select null)) as rowid
from mvct
cross apply string_split(price, ";")
)
select cte1.id, cte1.daykey, cte2.pricekey
from cte1
inner join cte2 on cte1.id = cte2.id
and cte1.rowid = cte2.rowid
and cte1.daykey = "02"
答案 2 :(得分:1)
您可以在https://www.sqlservercentral.com/articles/reaping-the-benefits-of-the-window-functions-in-t-sql-2上找到原始的DelimitedSplit8k_LEAD
功能代码
演示2列
select id, details.[day], details.price
from (
values
(1,'01;02;03;04','100;230;110;34.5')
,(2,'01;02;03;04','120;240;510;34.5')
) t (ID,[Day],Price)
cross apply (
select d.item [day], p.item price
from DelimitedSplit8k_LEAD([Day],';') d
join DelimitedSplit8k_LEAD(Price,';') p on d.ItemNumber = p.ItemNumber
) details
答案 3 :(得分:1)
如果可以在数据库中创建其他功能,则可以使用以下脚本获取所需的输出。
创建功能:
CREATE FUNCTION FIND_CHARINDEX
(@TargetStr VARCHAR(8000),
@SearchedStr VARCHAR(8000),
@Occurrence INT
)
RETURNS INT
AS
BEGIN
DECLARE @pos INT, @counter INT, @ret INT;
SET @pos = CHARINDEX(@TargetStr, @SearchedStr);
SET @counter = 1;
IF @Occurrence = 1
SET @ret = @pos;
ELSE
BEGIN
WHILE(@counter < @Occurrence)
BEGIN
SELECT @ret = CHARINDEX(@TargetStr, @SearchedStr, @pos + 1);
SET @counter = @counter + 1;
SET @pos = @ret;
END;
END;
RETURN(@ret);
END;
SELECT语句:
DECLARE @S_String VARCHAR(20) = '05'
DECLARE @S_String_New VARCHAR(20) = ';'+@S_String+';'
SELECT
REVERSE(
SUBSTRING(
REVERSE(
SUBSTRING(
';'+Day+';',
0,
(CHARINDEX(@S_String_New,';'+Day+';',0)+LEN(@S_String)) +1
)
),
0,
CHARINDEX(
';',
REVERSE(SUBSTRING(';'+Day+';',0, (CHARINDEX(@S_String_New,';'+Day+';',0)+LEN(@S_String)) +1)),
0
)
)
),
REVERSE(
SUBSTRING(
REVERSE(
SUBSTRING(
';'+PRICE+';',
0,
(
dbo.FIND_CHARINDEX(
';',
';'+PRICE+';',
(
LEN(SUBSTRING(';'+Day+';',0, (CHARINDEX(@S_String_New,';'+Day+';',0)+LEN(@S_String)) +1))
- LEN(REPLACE(SUBSTRING(';'+Day+';',0, (CHARINDEX(@S_String_New,';'+Day+';',0)+LEN(@S_String)) +1),';',''))+1
)
)
)
)
),
0,
CHARINDEX(
';',
REVERSE(
SUBSTRING(
';'+PRICE+';',
0,
(
dbo.FIND_CHARINDEX(
';',
';'+PRICE+';',
(
LEN(SUBSTRING(';'+Day+';',0, (CHARINDEX(@S_String_New,';'+Day+';',0)+LEN(@S_String)) +1))
- LEN(REPLACE(SUBSTRING(';'+Day+';',0, (CHARINDEX(@S_String_New,';'+Day+';',0)+LEN(@S_String)) +1),';',''))+1
)
)
)
)
),
1
)
)
)
FROM your_table
WHERE ';'+Day+';' LIKE '%'+@S_String_New+'%'