我有2个字符串和1个整数:
@categoryID int = 163,
@Ids nvarchar(2000) = '1,2,3',
@Names nvarchar(2000) = 'Bob,Joe,Alex'
我需要选择3列3行;最成就的是3行2列:
select @categoryID,items from FN_SplitStr(@Ids,',')
结果:
163,1
163,2
163,3
但是我不知道如何拆分两个字符串。
我尝试了很多方法,例如:
select @categoryID,items from FN_SplitStr((@Ids,@Names),',')
select @categoryID,items from FN_SplitStr(@Ids,','),items from FN_SplitStr(@Names,',')
预期输出:
163,1,Bob
163,2,Joe
163,3,Alex
注意1::我查看了数十个最相似的问题: How to split string and insert values into table in SQL Server和SQL Server : split multiple strings into one row each,但这个问题有所不同。
注意2::FN_SplitStr是用于在SQL中拆分字符串的函数。而且我正在尝试创建一个存储过程。
答案 0 :(得分:1)
根据您的期望输出,您必须两次使用交叉应用,然后创建某种排名,以确保获得正确的价值。由于ID和名称似乎没有任何关系,因此交叉应用会创建多行(当您将字符串拆分为名称和ID时)
也许有更好的方法,但这也可以提供预期的输出。您可以将此字符串拆分更改为本地函数。
第一个密集等级是为了确保我们得到三个唯一的名称,第二个密集等级是名称内根据ID和ID排序的等级,在子查询之外,您必须进行一些比较才能只获得3行。
Declare @categoryID int = 163,
@Ids nvarchar(2000) = '1,2,3',
@Names nvarchar(2000) = 'Bob,Joe,Alex'
select ConcatenatedValue, CategoryID, IDs, Names from (
select concat(@categoryID,',',a.value,',',b.value) ConcatenatedValue, @categoryID CategoryID,
A.value as IDs, b.value as Names , DENSE_RANK() over (order by b.value) as Rn,
DENSE_RANK() over (partition by b.value order by a.value) as Ranked
from string_split(@IDs,',') a
cross apply string_split(@names,',') B ) t
where Rn - Ranked = 0
输出:
答案 1 :(得分:0)
在您的存储过程中,对@Ids进行字符串分割,然后插入带有IDENTITY(1,1)列的#temp1表中。您将获得:
163,1,1
163,2,2
163,3,3
然后执行@Names的第二个字符串拆分,并插入带有IDENT(1,1)列的#temp2表。您将获得:
Bob,1
Joe,2
Alex,3
然后可以在#temp1.rowid =#temp2.rowid上使用#temp1和#temp2进行内部联接,并获得:
163,1,Bob
163,2,Joe
163,3,Alex
我希望这可以解决您的问题。
答案 2 :(得分:0)
您可以使用递归CTE来做到这一点:
with cte as (
select @categoryId as categoryId,
convert(varchar(max), left(@ids, charindex(',', @ids + ',') - 1)) as id,
convert(varchar(max), left(@names, charindex(',', @names + ',') - 1)) as name,
convert(varchar(max), stuff(@ids, 1, charindex(',', @ids + ','), '')) as rest_ids,
convert(varchar(max), stuff(@names, 1, charindex(',', @names + ','), '')) as rest_names
union all
select categoryId,
convert(varchar(max), left(rest_ids, charindex(',', rest_ids + ',') - 1)) as id,
convert(varchar(max), left(rest_names, charindex(',', rest_names + ',') - 1)) as name,
convert(varchar(max), stuff(rest_ids, 1, charindex(',', rest_ids + ','), '')) as rest_ids,
convert(varchar(max), stuff(rest_names, 1, charindex(',', rest_names + ','), '')) as rest_names
from cte
where rest_ids <> ''
)
select categoryid, id, name
from cte;
Here是db <>小提琴。
答案 3 :(得分:0)
您需要用记录号分割CSV值。为此,在将CSV列拆分为行时,您需要使用ROW_NUMBER()函数生成明智的唯一ID作为“ RID”之类的列。 您可以使用表值拆分功能或XML,如下所示。
请选中此复选框,让我们知道是否找到了您的解决方案。
DECLARE
@categoryID int = 163,
@Ids nvarchar(2000) = '1,2,3',
@Names nvarchar(2000) = 'Bob,Joe,Alex'
SELECT
@categoryID AS categoryID,
q.Id,
w.Names
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY f.value('.','VARCHAR(10)')) AS RID,
f.value('.','VARCHAR(10)') AS Id
FROM
(
SELECT
CAST('<a>' + REPLACE(@Ids,',','</a><a>') + '</a>' AS XML) AS idXML
) x
CROSS APPLY x.idXML.nodes('a') AS e(f)
) q
INNER JOIN
(
SELECT
ROW_NUMBER() OVER (ORDER BY h.value('.','VARCHAR(10)')) AS RID,
h.value('.','VARCHAR(10)') AS Names
FROM
(
SELECT
CAST('<a>' + REPLACE(@Names,',','</a><a>') + '</a>' AS XML) AS namesXML
) y
CROSS APPLY y.namesXML.nodes('a') AS g(h)
) w ON w.RID = q.RID