读取逗号分隔值并批量插入SQL表
Posted
技术标签:
【中文标题】读取逗号分隔值并批量插入SQL表【英文标题】:Read comma separated values and insert in SQL Table in batches 【发布时间】:2017-06-20 04:23:34 【问题描述】:我在一个 sql 表 Offer 中有 4 列。
id (PK auto increment), name , org , TourCode Varchar(MAX)
TourCode 包含逗号分隔的代码,例如(AVG123、JGH12 等)。
我有 40000 个旅游代码可用作逗号分隔值
我必须编写一个查询以在 Offer 表中插入 4000 行,每行包含 10 个以逗号分隔的旅游代码。 对于所有 4000 行,name 和 org 的值保持不变,例如“ABC”、“亚马逊”
例如
DECLARE @TourCodes VARCHAR(4000);
SET @TourCodes = 'AVG123,JGH12,AVasfG123,JGsdfH12,AVsdgG123,JsdgGH12 , A34G123,J56gGH12, A34G1df23,JgfGH12 ,......'
Output:
╦══════════╦════════════╦═══════════════════╗
║ name ║ org ║TourCode ║
╠══════════╬═══════════ ╬═══════════════════╣
║ ABC ║ Amazon ║AVG123,JGH12 ║
║ ABC ║ Amazon ║AVasfG123,JGsdfH12 ║
║ ABC ║ Amazon ║AVsdgG123,JsdgGH12 ║
║ ABC ║ Amazon ║A34G123,J56gGH12 ║
║ ABC ║ Amazon ║A34G1df23,JgfGH12 ║
什么应该是我最好的方法。
我正在使用 SQL Server 。 提前致谢。
【问题讨论】:
从 SQL-SERVER 2016 开始,表值函数string_split()
可能在这里有用。
@cars10 string_split() 将根据逗号拆分值,每行将有 1 个旅游代码,总记录将是 400。我的要求是,我想要 2(示例)旅游代码每行和总行将是 200
【参考方案1】:
这是如何将逗号分隔值拆分为表格(取自How to split a comma-separated value to columns)
CREATE FUNCTION Split (
@InputString VARCHAR(8000),
@Delimiter VARCHAR(50)
)
RETURNS @Items TABLE (
Item VARCHAR(8000)
)
AS
BEGIN
IF @Delimiter = ' '
BEGIN
SET @Delimiter = ','
SET @InputString = REPLACE(@InputString, ' ', @Delimiter)
END
IF (@Delimiter IS NULL OR @Delimiter = '')
SET @Delimiter = ','
--INSERT INTO @Items VALUES (@Delimiter) -- Diagnostic
--INSERT INTO @Items VALUES (@InputString) -- Diagnostic
DECLARE @Item VARCHAR(8000)
DECLARE @ItemList VARCHAR(8000)
DECLARE @DelimIndex INT
SET @ItemList = @InputString
SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
WHILE (@DelimIndex != 0)
BEGIN
SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
INSERT INTO @Items VALUES (@Item)
-- Set @ItemList = @ItemList minus one less item
SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)
SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
END -- End WHILE
IF @Item IS NOT NULL -- At least one delimiter was encountered in @InputString
BEGIN
SET @Item = @ItemList
INSERT INTO @Items VALUES (@Item)
END
-- No delimiters were encountered in @InputString, so just return @InputString
ELSE INSERT INTO @Items VALUES (@InputString)
RETURN
END -- End Function
GO
之后
使用此代码
DECLARE @TourCodes varchar(4000)
SET @TourCodes = 'AAAAA,BBBBB,CCCCC,DDDD,EEEE,FFFF , GGG,HHHHH, IIIII,JJJJJ'
DECLARE @T as table (ID int identity, Name varchar(255), Org varchar(255), TourCode varchar(255))
INSERT @T (Name, Org, TourCode)
select 'ABC', 'AMAZON', Item from dbo.split(@TourCodes,',')
Select A.Name, A.Org, ISNULL(A.TourCode, '') + ',' + ISNULL(B.TourCode, '')
from @T A INNER JOIN @T B
ON A.ID = B.ID-1
AND A.ID%2 = 0
【讨论】:
这给出了不正确的结果。我想要每个值 2 个旅游码,它给出随机结果 我修改了查询,现在试试 嘿@asmgx ..谢谢你的回复。但是这个查询有问题。如果我想要每行10个Tourcode怎么办。我必须修改整个查询。 在这种情况下,您最好循环使用逗号分隔的值,在 10 个逗号之后将逗号更改为分号,然后用分号分隔【参考方案2】:那就先试试这个,再试试用分号分割SP
此函数将用分号分隔每 N 个 Tours
create FUNCTION GroupBySemicolon (
@TourCodes VARCHAR(8000),
@HowManyTours int
)
RETURNS varchar(8000)
AS
BEGIN
DECLARE @i int
DECLARE @Pos int
SET @i = 0
SET @Pos = 1
WHILE @Pos <> 0
BEGIN
SET @i= @i+1
SET @Pos = CHARINDEX( ',', @TourCodes,@Pos + 1)
--SELECT @Pos
IF @i = @HowManyTours and @Pos > 0
BEGIN
SET @i = 0
SET @TourCodes = LEFT(@TourCodes,@Pos-1) + ';' + RIGHT(@TourCodes, LEN(@TourCodes) - @Pos)
END
END
RETURN @TourCodes
END
select dbo.GroupBySemicolon( '111,222222,333,44,555555,66 ,7777,8888, 99999,000000', 4)
【讨论】:
而不是 semicolumn ,下一组 4 应该在下一行。如果有 12 个旅游代码,而 HowManyTours 是 4,那么我们应该有 3 行,每行 4 个旅游代码! SELECT 'ABC', 'Amazon', dbo.Split(dbo.GroupBySemicolon( '111,222222,333,44,555555,66 ,7777,8888, 99999,000000', 4), ';') 如果这回答了您的问题,则将其标记为 ANSWER【参考方案3】:那么这个解决方案呢?
DECLARE @TourCodes VARCHAR(4000);
SET @TourCodes = ' AVG123 , JGH12,AVasfG123,JGsdfH12,AVsdgG123,JsdgGH12 , A34G123,J56gGH12, A34G1df23,JgfGH12';
with rcrs AS (
select rtrim(ltrim(LEFT(@TourCodes,charindex(',',@TourCodes)-1))) first,
SUBSTRING(@TourCodes+',',charindex(',',@TourCodes)+1,4000) other,
0 flg
union all
select rtrim(ltrim(LEFT(other,charindex(',',other)-1))) first,
SUBSTRING(other,charindex(',',other)+1,4000) other ,
flg+1 flg FROM rcrs WHERE charindex(',',other)>0
)
SELECT a.first one,b.first two from rcrs a
INNER JOIN rcrs b ON b.flg=a.flg+1 WHERE a.flg%2=0
在递归 CTE 中,字符串从头开始拆分。
值得注意的是,我在递归 CTE 的第一部分中为原始字符串添加了一个额外的 ','
后缀。这可以确保所有单词都被 CTE “吃掉”,然后可以由主选择使用模 (%
) 技巧来确定哪个部分进入列 one
或 two
。
这个例子的结果是:
one two
AVG123 JGH12
AVasfG123 JGsdfH12
AVsdgG123 JsdgGH12
A34G123 J56gGH12
A34G1df23 JgfGH12
在这里查看演示:http://rextester.com/WAA6224
编辑
显然我手头的时间太多了 ;-) ... 因此,我继续尝试是否可以按照 OP 似乎想要的方式将所有内容重新组合成一个十列集合。我仍然不完全清楚结果的外观,但这是另一个镜头:
DECLARE @TourCodes VARCHAR(4000);
SET @TourCodes = REPLACE(REPLACE(
' AVG123 , JGH12,AVasfG123,JGsdfH12,AVsdgG123,JsdgGH12 , A34G123,J56gGH12, A34G1df23,JgfGH12,
AVG1234 , JGH126,AVasfG1238,JGsdfH122,AVsdgG1235,JsdgGH127 , A34G1239,J56gGH12a, A34G1df23c,JgfGH12e,
AVG1235 , JGH127,AVasfG1239,JGsdfH123,AVsdgG1236,JsdgGH128 , A34G1230,J56gGH12b, A34G1df23d,JgfGH12f',
char(10),''),char(13),''); -- this is just a slightly extended sample input string
with rcrs AS (
select rtrim(ltrim(LEFT(@TourCodes,charindex(',',@TourCodes)-1))) first,
SUBSTRING(@TourCodes+',',charindex(',',@TourCodes)+1,4000) other, 0 flg
union all
select rtrim(ltrim(LEFT(other,charindex(',',other)-1))) first,
SUBSTRING(other,charindex(',',other)+1,4000) other , flg+1 flg FROM rcrs WHERE charindex(',',other)>0 and flg<30
), cmbn AS (
SELECT a.flg/20 ii,(a.flg/2)%10 ij ,a.first+','+b.first tc FROM rcrs a
LEFT JOIN rcrs b ON b.flg=a.flg+1
WHERE a.flg%2=0
)
SELECT ii,'ABC' name,'Amazon' org, MAX(CASE ij WHEN 0 THEN tc END) tc1,
MAX(CASE ij WHEN 1 THEN tc END) tc2,
MAX(CASE ij WHEN 2 THEN tc END) tc3,
MAX(CASE ij WHEN 3 THEN tc END) tc4,
MAX(CASE ij WHEN 4 THEN tc END) tc5,
MAX(CASE ij WHEN 5 THEN tc END) tc6,
MAX(CASE ij WHEN 6 THEN tc END) tc7,
MAX(CASE ij WHEN 7 THEN tc END) tc8,
MAX(CASE ij WHEN 8 THEN tc END) tc9,
MAX(CASE ij WHEN 9 THEN tc END) tc10
FROM cmbn GROUP BY ii
结果如下:
ii name org tc1 tc2 tc3 tc4 tc5 tc6 tc7 tc8 tc9 tc10
0 ABC Amazon AVG123,JGH12 AVasfG123,JGsdfH12 AVsdgG123,JsdgGH12 A34G123,J56gGH12 A34G1df23,JgfGH12 AVG1234,JGH126 AVasfG1238,JGsdfH122 AVsdgG1235,JsdgGH127 A34G1239,J56gGH12a A34G1df23c,JgfGH12e
1 ABC Amazon AVG1235,JGH127 AVasfG1239,JGsdfH123 AVsdgG1236,JsdgGH128 A34G1230,J56gGH12b A34G1df23d,JgfGH12f
请看这里:http://rextester.com/ZJNV34690
或者,如果您希望将所有十个旅游代码放在一列中,您可以这样做
SELECT ii,'ABC' name,'Amazon' org,
MAX(CASE ij WHEN 0 THEN tc END)+' '+
COALESCE(MAX(CASE ij WHEN 1 THEN tc END)+' ','')+
COALESCE(MAX(CASE ij WHEN 2 THEN tc END)+' ','')+
COALESCE(MAX(CASE ij WHEN 3 THEN tc END)+' ','')+
COALESCE(MAX(CASE ij WHEN 4 THEN tc END)+' ','')+
COALESCE(MAX(CASE ij WHEN 5 THEN tc END)+' ','')+
COALESCE(MAX(CASE ij WHEN 6 THEN tc END)+' ','')+
COALESCE(MAX(CASE ij WHEN 7 THEN tc END)+' ','')+
COALESCE(MAX(CASE ij WHEN 8 THEN tc END)+' ','')+
COALESCE(MAX(CASE ij WHEN 9 THEN tc END)+' ','') tourCodes
FROM cmbn GROUP BY ii
在主选择中。看这里http://rextester.com/AQCG28977
结果:
ii name org tourCodes
0 ABC Amazon AVG123,JGH12 AVasfG123,JGsdfH12 AVsdgG123,JsdgGH12 A34G123,J56gGH12 A34G1df23,JgfGH12 AVG1234,JGH126 AVasfG1238,JGsdfH122 AVsdgG1235,JsdgGH127 A34G1239,J56gGH12a A34G1df23c,JgfGH12e
1 ABC Amazon AVG1235,JGH127 AVasfG1239,JGsdfH123 AVsdgG1236,JsdgGH128 A34G1230,J56gGH12b A34G1df23d,JgfGH12f
【讨论】:
要求有点不同。我有 40000 个旅游代码可用作逗号分隔值我必须编写一个查询以在 Offer 表中插入 4000 行,每行包含 10 个旅游代码。每行中的 10 个旅游代码应该用逗号分隔。 嗯,这不是免费的编码服务。如果您可以使用我的 sn-p 找到自己的解决方案,那将是 *** 的最佳精神。否则:继续寻找/尝试。祝你好运! ;-)以上是关于读取逗号分隔值并批量插入SQL表的主要内容,如果未能解决你的问题,请参考以下文章
在 SQL Server 中批量插入部分引用的 CSV 文件