循环并在 SQL 中插入多个逗号分隔的列表
Loop and insert more than one comma separated List in SQL
我希望遍历两个逗号分隔值并执行插入
举个例子让我们考虑两个变量
Declare @Qid= 1,4,6,7,8 @Answers = 4,4,3,2,3
set @pos = 0
set @len = 0
WHILE CHARINDEX(',', @Answers, @pos+1)>0
BEGIN
set @len = CHARINDEX(',', @Answers, @pos+1) - @pos
set @value = SUBSTRING(@Answers, @pos, @len)
insert into table values(@fdid,@Qid,@fusid, @value) -- i need Qid also
set @pos = CHARINDEX(',', @Answers, @pos+@len) +1
END
使用这个循环我可以提取 @Answers
并可以执行插入。但我希望提取 @Qid
并插入循环中。
编辑
为了更清楚,它是一个反馈模块。我的结果 table 有 Qid 和 Answer 字段。答案是评分(1 到 5)。我们在变量@Qid 和@Answers 中获得的值是连续的。这意味着第一个答案将针对第一个问题,依此类推。
编辑
根据 Shnugo 的回答
Declare @Qid varchar(100)= '1,4,6,7,8', @Answers varchar(100)= '4,4,3,2,3'
DECLARE @tbl TABLE(ID INT IDENTITY, Questions VARCHAR(100),Answers VARCHAR(100));
INSERT INTO @tbl VALUES(@Qid,@Answers)
INSERT INTO table(FeedbackId,QuestionId,FeedbackUserId,Answer)
SELECT 1,
A.qXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS QuestionNumber,3
,A.aXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS AnwerNumber
FROM @tbl t
CROSS APPLY(SELECT CAST('<x>' + REPLACE(@Qid,',','</x><x>') + '</x>' AS XML)
,CAST('<x>' + REPLACE(@Answers,',','</x><x>') + '</x>' AS XML)) A(qXml,aXml)
CROSS APPLY(SELECT TOP(A.qXml.value('count(/x)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) B(QuestionCount)
如果您使用 SQL Server 2016 或更高版本,您可以尝试使用下一个基于 JSON 的方法来根据输入字符串中的位置映射问题和答案。您需要将输入字符串转换为有效的 JSON 数组,然后使用具有默认模式的 OPENJSON()
来解析这些数组。结果是 table,包含 key
、value
和 type
列,key
列包含指定数组中元素的索引。
请注意,STRING_SPLIT()
函数不保证行的顺序,输出行可能是任何顺序。
声明:
DECLARE @Qid nvarchar(max) = N'1,4,6,7,8'
DECLARE @Answers nvarchar(max) = N'4,4,3,2,3'
-- Build your INSERT statement as you expect
-- INSERT INTO Table ...
SELECT j1.[value] AS Qid, j2.[value] AS Answers
FROM OPENJSON(CONCAT(N'[', @Qid, N']')) j1
JOIN OPENJSON(CONCAT(N'[', @Answers, N']')) j2 ON j1.[key] = j2.[key]
SELECT 语句的结果:
Qid Answers
1 4
4 4
6 3
7 2
8 3
您没有描述问题与答案的关系。我觉得是一对一的关系,为此,我给出了答案。
declare @Qid varchar(200)= '1,4,6,7,8' , @Answers varchar(200) = '4,4,3,2,3'
;with cte
as(
select id, data qid from dbo.Split (@qid, ',')
),
cte1 as
(
select id, data ansid from dbo.Split (@answers, ',')
)
--insert into tablename
select
qid, ansid from cte join cte1 on cte.id = cte1.id
结果将是:
qid ansid
1 4
4 4
6 3
7 2
8 3
查看更高版本的 sqlserver 的其他选项:Split function equivalent in T-SQL?
我更喜欢 (需要 v2016+)。
如果您使用 2016 年以下的 SQL-服务器,您可能会使用这个位置安全的基于 XML 的解决方案:
一个 模型 table 用两个不同的行来模拟您的问题。
DECLARE @tbl TABLE(ID INT IDENTITY, Questions VARCHAR(100),Answers VARCHAR(100));
INSERT INTO @tbl VALUES('1,4,6,7,8','4,4,3,2,3')
,('1,2,3','4,5,6');
--查询
SELECT t.*
,A.qXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS QuestionNumber
,A.aXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS AnwerNumber
FROM @tbl t
CROSS APPLY(SELECT CAST('<x>' + REPLACE(t.Questions,',','</x><x>') + '</x>' AS XML)
,CAST('<x>' + REPLACE(t.Answers,',','</x><x>') + '</x>' AS XML)) A(qXml,aXml)
CROSS APPLY(SELECT TOP(A.qXml.value('count(/x)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) B(QuestionCount);
简而言之:
我们需要 CROSS APPLY
和一些字符串方法来将 1,2,3
之类的内容转换为 xml 之类的 <x>1</x><x>2</x><x>3</x>
.
现在我们可以使用 value()
和 XQuery count()
来查找问题的实际数量。
我们还需要一个带有计算 TOP()
子句的 CROSS APPLY
来获得一组从 1 到 n 的 运行 数字,n=countOfQuestions。我这样做反对 master..spt_values
。这只是一个填充良好的标准 table...我们不需要值,只需要任何集合来创建计数器...
最后,我们可以将 .value()
与 sql:column()
结合使用,以便按位置获取问题和相应的答案。
更新:非表格数据
如果您没有将这些 CSV 参数作为 table 获取,您可以使用:
Declare @Qid varchar(100)= '1,4,6,7,8', @Answers varchar(100)= '4,4,3,2,3'
--INSERT INTO table(FeedbackId,QuestionId,FeedbackUserId,Answer)
SELECT 1
,A.qXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS QuestionNumber
,3
,A.aXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS AnwerNumber
FROM (SELECT CAST('<x>' + REPLACE(@Qid,',','</x><x>') + '</x>' AS XML)
,CAST('<x>' + REPLACE(@Answers,',','</x><x>') + '</x>' AS XML)) A(qXml,aXml)
CROSS APPLY(SELECT TOP(A.qXml.value('count(/x)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) B(QuestionCount);
我希望遍历两个逗号分隔值并执行插入
举个例子让我们考虑两个变量
Declare @Qid= 1,4,6,7,8 @Answers = 4,4,3,2,3
set @pos = 0
set @len = 0
WHILE CHARINDEX(',', @Answers, @pos+1)>0
BEGIN
set @len = CHARINDEX(',', @Answers, @pos+1) - @pos
set @value = SUBSTRING(@Answers, @pos, @len)
insert into table values(@fdid,@Qid,@fusid, @value) -- i need Qid also
set @pos = CHARINDEX(',', @Answers, @pos+@len) +1
END
使用这个循环我可以提取 @Answers
并可以执行插入。但我希望提取 @Qid
并插入循环中。
编辑 为了更清楚,它是一个反馈模块。我的结果 table 有 Qid 和 Answer 字段。答案是评分(1 到 5)。我们在变量@Qid 和@Answers 中获得的值是连续的。这意味着第一个答案将针对第一个问题,依此类推。
编辑
根据 Shnugo 的回答
Declare @Qid varchar(100)= '1,4,6,7,8', @Answers varchar(100)= '4,4,3,2,3'
DECLARE @tbl TABLE(ID INT IDENTITY, Questions VARCHAR(100),Answers VARCHAR(100));
INSERT INTO @tbl VALUES(@Qid,@Answers)
INSERT INTO table(FeedbackId,QuestionId,FeedbackUserId,Answer)
SELECT 1,
A.qXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS QuestionNumber,3
,A.aXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS AnwerNumber
FROM @tbl t
CROSS APPLY(SELECT CAST('<x>' + REPLACE(@Qid,',','</x><x>') + '</x>' AS XML)
,CAST('<x>' + REPLACE(@Answers,',','</x><x>') + '</x>' AS XML)) A(qXml,aXml)
CROSS APPLY(SELECT TOP(A.qXml.value('count(/x)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) B(QuestionCount)
如果您使用 SQL Server 2016 或更高版本,您可以尝试使用下一个基于 JSON 的方法来根据输入字符串中的位置映射问题和答案。您需要将输入字符串转换为有效的 JSON 数组,然后使用具有默认模式的 OPENJSON()
来解析这些数组。结果是 table,包含 key
、value
和 type
列,key
列包含指定数组中元素的索引。
请注意,STRING_SPLIT()
函数不保证行的顺序,输出行可能是任何顺序。
声明:
DECLARE @Qid nvarchar(max) = N'1,4,6,7,8'
DECLARE @Answers nvarchar(max) = N'4,4,3,2,3'
-- Build your INSERT statement as you expect
-- INSERT INTO Table ...
SELECT j1.[value] AS Qid, j2.[value] AS Answers
FROM OPENJSON(CONCAT(N'[', @Qid, N']')) j1
JOIN OPENJSON(CONCAT(N'[', @Answers, N']')) j2 ON j1.[key] = j2.[key]
SELECT 语句的结果:
Qid Answers
1 4
4 4
6 3
7 2
8 3
您没有描述问题与答案的关系。我觉得是一对一的关系,为此,我给出了答案。
declare @Qid varchar(200)= '1,4,6,7,8' , @Answers varchar(200) = '4,4,3,2,3'
;with cte
as(
select id, data qid from dbo.Split (@qid, ',')
),
cte1 as
(
select id, data ansid from dbo.Split (@answers, ',')
)
--insert into tablename
select
qid, ansid from cte join cte1 on cte.id = cte1.id
结果将是:
qid ansid
1 4
4 4
6 3
7 2
8 3
查看更高版本的 sqlserver 的其他选项:Split function equivalent in T-SQL?
我更喜欢
如果您使用 2016 年以下的 SQL-服务器,您可能会使用这个位置安全的基于 XML 的解决方案:
一个 模型 table 用两个不同的行来模拟您的问题。
DECLARE @tbl TABLE(ID INT IDENTITY, Questions VARCHAR(100),Answers VARCHAR(100));
INSERT INTO @tbl VALUES('1,4,6,7,8','4,4,3,2,3')
,('1,2,3','4,5,6');
--查询
SELECT t.*
,A.qXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS QuestionNumber
,A.aXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS AnwerNumber
FROM @tbl t
CROSS APPLY(SELECT CAST('<x>' + REPLACE(t.Questions,',','</x><x>') + '</x>' AS XML)
,CAST('<x>' + REPLACE(t.Answers,',','</x><x>') + '</x>' AS XML)) A(qXml,aXml)
CROSS APPLY(SELECT TOP(A.qXml.value('count(/x)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) B(QuestionCount);
简而言之:
我们需要 CROSS APPLY
和一些字符串方法来将 1,2,3
之类的内容转换为 xml 之类的 <x>1</x><x>2</x><x>3</x>
.
现在我们可以使用 value()
和 XQuery count()
来查找问题的实际数量。
我们还需要一个带有计算 TOP()
子句的 CROSS APPLY
来获得一组从 1 到 n 的 运行 数字,n=countOfQuestions。我这样做反对 master..spt_values
。这只是一个填充良好的标准 table...我们不需要值,只需要任何集合来创建计数器...
最后,我们可以将 .value()
与 sql:column()
结合使用,以便按位置获取问题和相应的答案。
更新:非表格数据
如果您没有将这些 CSV 参数作为 table 获取,您可以使用:
Declare @Qid varchar(100)= '1,4,6,7,8', @Answers varchar(100)= '4,4,3,2,3'
--INSERT INTO table(FeedbackId,QuestionId,FeedbackUserId,Answer)
SELECT 1
,A.qXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS QuestionNumber
,3
,A.aXml.value('(/x[sql:column("B.QuestionCount")])[1]','int') AS AnwerNumber
FROM (SELECT CAST('<x>' + REPLACE(@Qid,',','</x><x>') + '</x>' AS XML)
,CAST('<x>' + REPLACE(@Answers,',','</x><x>') + '</x>' AS XML)) A(qXml,aXml)
CROSS APPLY(SELECT TOP(A.qXml.value('count(/x)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) B(QuestionCount);