Sql 在结果集中为输入字符串中的每个换行符创建新行
我正在尝试将逗号分隔的值字符串转换为表。到目前为止,我已经能够根据输入的字符串创建表,但我也尝试为每个换行添加一个新行。我认为这可以通过循环字符串和在每条换行线上拆分来实现。不幸的是,不能使用string\u SPLIT,然后为每个换行添加一个联合到动态选择中。然而,这听起来可能是最没有效率的方法 这是我目前掌握的代码:Sql 在结果集中为输入字符串中的每个换行符创建新行,sql,sql-server,Sql,Sql Server,我正在尝试将逗号分隔的值字符串转换为表。到目前为止,我已经能够根据输入的字符串创建表,但我也尝试为每个换行添加一个新行。我认为这可以通过循环字符串和在每条换行线上拆分来实现。不幸的是,不能使用string\u SPLIT,然后为每个换行添加一个联合到动态选择中。然而,这听起来可能是最没有效率的方法 这是我目前掌握的代码: DECLARE @ps_String varchar(max), @ps_Delimiter char(1), @ls_XML xml,
DECLARE @ps_String varchar(max),
@ps_Delimiter char(1),
@ls_XML xml,
@ln_Count INT,
@ls_SQL VARCHAR(MAX) = ''
SELECT @ps_String = 'ab,cd,ef,gh,ij,
kl, mn, op, qr,st',
@ps_Delimiter = ','
SET @ls_SQL = '
DECLARE @ls_XML XML
SELECT @ls_XML = CONVERT(xml,'' <root> <myvalue>'' +
REPLACE('''+@ps_String+''','''+@ps_Delimiter+''',''</myvalue> <myvalue>'') + ''</myvalue> </root> '')
SELECT DISTINCT'
SET @ln_Count = 1
WHILE (@ln_Count <= LEN(@ps_String) - LEN(REPLACE(@ps_String, @ps_Delimiter, '')) + 1 ) BEGIN
SET @ls_SQL = @ls_SQL + '
T.c.value(''(/root/myvalue)['+CONVERT(VARCHAR, @ln_Count)+']'',''VARCHAR(20)''),'
SET @ln_Count = @ln_Count + 1
END
SET @ls_SQL = LEFT(@ls_SQL, LEN(@ls_SQL) - 1)
SET @ls_SQL = @ls_SQL + '
FROM @ls_XML.nodes(''/root/myvalue'') T(c)'
PRINT @ls_SQL
--EXEC(@ls_SQL)
SQL Server 2014这里有一个明确的黑客,您可以尝试:
DECLARE @ps_String VARCHAR(MAX) = 'ab,cd,ef,gh,ij,
kl, mn, op, qr,st';
/* Clean-up and divide the provided string into rows based on CR/LF */
SET @ps_String = (
SELECT
REPLACE ( cleanString, ',', '</val><val>' ) AS myXml
FROM (
SELECT '<rows><row><val>' + REPLACE ( REPLACE ( @ps_String, CHAR(13), '' ), CHAR(10), '</val></row><row><val>' ) + '</val></row></rows>' AS rws
) AS getRows
CROSS APPLY ( SELECT REPLACE ( getRows.rws, ',<', '<' ) AS cleanString ) AS stripTrailingComma
);
/* Add a unique row id to each row */
DECLARE @id INT = 0;
WHILE CHARINDEX ( '<row>', @ps_String ) > 0
BEGIN
SET @id = @id + 1;
SET @ps_String = STUFF ( @ps_String, CHARINDEX ( '<row>', @ps_String ) + 4, 0, FORMATMESSAGE ( ' id="%i"', @id ) );
END
/* Show results */
SELECT
r.v.value( '../@id', 'INT' ) AS row_id,
ROW_NUMBER() OVER ( PARTITION BY r.v.value( '../@id', 'INT' ) ORDER BY r.v.value( '../@id', 'INT' ) ) AS val_id,
LTRIM( RTRIM( r.v.value( '.', 'VARCHAR(255)' ) ) ) AS val
FROM (
SELECT CAST ( @ps_String AS XML ) AS rws
) AS myXml
CROSS APPLY rws.nodes( '//rows/row/val' ) r(v);
这里有一个明确的方法,你可以试试:
DECLARE @ps_String VARCHAR(MAX) = 'ab,cd,ef,gh,ij,
kl, mn, op, qr,st';
/* Clean-up and divide the provided string into rows based on CR/LF */
SET @ps_String = (
SELECT
REPLACE ( cleanString, ',', '</val><val>' ) AS myXml
FROM (
SELECT '<rows><row><val>' + REPLACE ( REPLACE ( @ps_String, CHAR(13), '' ), CHAR(10), '</val></row><row><val>' ) + '</val></row></rows>' AS rws
) AS getRows
CROSS APPLY ( SELECT REPLACE ( getRows.rws, ',<', '<' ) AS cleanString ) AS stripTrailingComma
);
/* Add a unique row id to each row */
DECLARE @id INT = 0;
WHILE CHARINDEX ( '<row>', @ps_String ) > 0
BEGIN
SET @id = @id + 1;
SET @ps_String = STUFF ( @ps_String, CHARINDEX ( '<row>', @ps_String ) + 4, 0, FORMATMESSAGE ( ' id="%i"', @id ) );
END
/* Show results */
SELECT
r.v.value( '../@id', 'INT' ) AS row_id,
ROW_NUMBER() OVER ( PARTITION BY r.v.value( '../@id', 'INT' ) ORDER BY r.v.value( '../@id', 'INT' ) ) AS val_id,
LTRIM( RTRIM( r.v.value( '.', 'VARCHAR(255)' ) ) ) AS val
FROM (
SELECT CAST ( @ps_String AS XML ) AS rws
) AS myXml
CROSS APPLY rws.nodes( '//rows/row/val' ) r(v);
下面的方法是检索动态SQL语句构造所需的任何字符串拆分信息的一种方法。它由2个递归公共表表达式组成,首先拆分行,然后拆分列 以防你更愿意看到它的行动
declare @data nvarchar(100) = N'ab,cd,ef,gh,ij,
kl, mn, op, qr,st';
declare @rowDelimiter nvarchar(1) = char(10);
declare @colDelimiter nvarchar(1) = ',';
with cte_rows as
(
select 1 as RowNum,
@data as Data,
1 as Starts,
charindex(@rowDelimiter, @data) as Pos
union all
select cr.RowNum + 1,
cr.Data,
cr.Pos+1,
charindex(@rowDelimiter, cr.Data, cr.Pos+1)
from cte_rows cr
where cr.Pos > 0
),
cte_cols as
(
select cr.RowNum,
1 as ColNum,
substring(cr.data, cr.Starts, case when cr.Pos > 0 then cr.Pos-cr.Starts else len(cr.data) end) as RowData,
1 as Starts,
charindex(@colDelimiter, substring(cr.data, cr.Starts, case when cr.Pos > 0 then cr.Pos-cr.Starts else len(cr.data) end)) as Pos
from cte_rows cr
union all
select cc.RowNum,
cc.ColNum + 1,
cc.RowData,
cc.Pos+1,
charindex(@colDelimiter, cc.RowData, cc.Pos+1)
from cte_cols cc
where cc.Pos > 0
)
select cc.RowNum,
cc.ColNum,
rtrim(ltrim(substring(cc.RowData, cc.Starts, case when cc.Pos>0 then cc.Pos-cc.Starts else len(cc.RowData) end))) as ColVal
from cte_cols cc
order by cc.RowNum, cc.ColNum;
结果:
RowNum ColNum ColVal
------ ------ ------
1 1 ab
1 2 cd
1 3 ef
1 4 gh
1 5 ij
1 6
2 1 kl
2 2 mn
2 3 op
2 4 qr
2 5 st
第1行有6列,第2行有5列,因为第1行后面有逗号,第2行没有。在ColVal上筛选此数据集,或在cte_cols RowData中删除子字符串选择后的尾随逗号
在创建动态SQL语句后,在上一次查询后添加固定轴以预览潜在输出:
declare @data nvarchar(100) = N'ab,cd,ef,gh,ij,
kl, mn, op, qr,st';
declare @rowDelimiter nvarchar(1) = char(10);
declare @colDelimiter nvarchar(1) = ',';
-- split rows + columns and pivot
with cte_rows as
(
select 1 as RowNum,
@data as Data,
1 as Starts,
charindex(@rowDelimiter, @data) as Pos
union all
select cr.RowNum + 1,
cr.Data,
cr.Pos+1,
charindex(@rowDelimiter, cr.Data, cr.Pos+1)
from cte_rows cr
where cr.Pos > 0
),
cte_cols as
(
select cr.RowNum,
1 as ColNum,
substring(cr.data, cr.Starts, case when cr.Pos > 0 then cr.Pos-cr.Starts else len(cr.data) end) as RowData,
1 as Starts,
charindex(@colDelimiter, substring(cr.data, cr.Starts, case when cr.Pos > 0 then cr.Pos-cr.Starts else len(cr.data) end)) as Pos
from cte_rows cr
union all
select cc.RowNum,
cc.ColNum + 1,
cc.RowData,
cc.Pos+1,
charindex(@colDelimiter, cc.RowData, cc.Pos+1)
from cte_cols cc
where cc.Pos > 0
),
cte_values as
(
select cc.RowNum,
cc.ColNum,
rtrim(ltrim(substring(cc.RowData, cc.Starts, case when cc.Pos>0 then cc.Pos-cc.Starts else len(cc.RowData) end))) as ColVal
from cte_cols cc
)
select p.RowNum,
p.[1] as Col1,
p.[2] as Col2,
p.[3] as Col3,
p.[4] as Col4,
p.[5] as Col5,
p.[6] as Col6
from cte_values cv
pivot (max(cv.ColVal) for cv.ColNum in ([1], [2], [3], [4], [5], [6])) p
order by p.RowNum;
这使得:
RowNum Col1 Col2 Col3 Col4 Col5 Col6
------ ------- ------- ------- ------- ------- -------
1 ab cd ef gh ij
2 kl mn op qr st null
下面的方法是检索动态SQL语句构造所需的任何字符串拆分信息的一种方法。它由2个递归公共表表达式组成,首先拆分行,然后拆分列 以防你更愿意看到它的行动
declare @data nvarchar(100) = N'ab,cd,ef,gh,ij,
kl, mn, op, qr,st';
declare @rowDelimiter nvarchar(1) = char(10);
declare @colDelimiter nvarchar(1) = ',';
with cte_rows as
(
select 1 as RowNum,
@data as Data,
1 as Starts,
charindex(@rowDelimiter, @data) as Pos
union all
select cr.RowNum + 1,
cr.Data,
cr.Pos+1,
charindex(@rowDelimiter, cr.Data, cr.Pos+1)
from cte_rows cr
where cr.Pos > 0
),
cte_cols as
(
select cr.RowNum,
1 as ColNum,
substring(cr.data, cr.Starts, case when cr.Pos > 0 then cr.Pos-cr.Starts else len(cr.data) end) as RowData,
1 as Starts,
charindex(@colDelimiter, substring(cr.data, cr.Starts, case when cr.Pos > 0 then cr.Pos-cr.Starts else len(cr.data) end)) as Pos
from cte_rows cr
union all
select cc.RowNum,
cc.ColNum + 1,
cc.RowData,
cc.Pos+1,
charindex(@colDelimiter, cc.RowData, cc.Pos+1)
from cte_cols cc
where cc.Pos > 0
)
select cc.RowNum,
cc.ColNum,
rtrim(ltrim(substring(cc.RowData, cc.Starts, case when cc.Pos>0 then cc.Pos-cc.Starts else len(cc.RowData) end))) as ColVal
from cte_cols cc
order by cc.RowNum, cc.ColNum;
结果:
RowNum ColNum ColVal
------ ------ ------
1 1 ab
1 2 cd
1 3 ef
1 4 gh
1 5 ij
1 6
2 1 kl
2 2 mn
2 3 op
2 4 qr
2 5 st
第1行有6列,第2行有5列,因为第1行后面有逗号,第2行没有。在ColVal上筛选此数据集,或在cte_cols RowData中删除子字符串选择后的尾随逗号
在创建动态SQL语句后,在上一次查询后添加固定轴以预览潜在输出:
declare @data nvarchar(100) = N'ab,cd,ef,gh,ij,
kl, mn, op, qr,st';
declare @rowDelimiter nvarchar(1) = char(10);
declare @colDelimiter nvarchar(1) = ',';
-- split rows + columns and pivot
with cte_rows as
(
select 1 as RowNum,
@data as Data,
1 as Starts,
charindex(@rowDelimiter, @data) as Pos
union all
select cr.RowNum + 1,
cr.Data,
cr.Pos+1,
charindex(@rowDelimiter, cr.Data, cr.Pos+1)
from cte_rows cr
where cr.Pos > 0
),
cte_cols as
(
select cr.RowNum,
1 as ColNum,
substring(cr.data, cr.Starts, case when cr.Pos > 0 then cr.Pos-cr.Starts else len(cr.data) end) as RowData,
1 as Starts,
charindex(@colDelimiter, substring(cr.data, cr.Starts, case when cr.Pos > 0 then cr.Pos-cr.Starts else len(cr.data) end)) as Pos
from cte_rows cr
union all
select cc.RowNum,
cc.ColNum + 1,
cc.RowData,
cc.Pos+1,
charindex(@colDelimiter, cc.RowData, cc.Pos+1)
from cte_cols cc
where cc.Pos > 0
),
cte_values as
(
select cc.RowNum,
cc.ColNum,
rtrim(ltrim(substring(cc.RowData, cc.Starts, case when cc.Pos>0 then cc.Pos-cc.Starts else len(cc.RowData) end))) as ColVal
from cte_cols cc
)
select p.RowNum,
p.[1] as Col1,
p.[2] as Col2,
p.[3] as Col3,
p.[4] as Col4,
p.[5] as Col5,
p.[6] as Col6
from cte_values cv
pivot (max(cv.ColVal) for cv.ColNum in ([1], [2], [3], [4], [5], [6])) p
order by p.RowNum;
这使得:
RowNum Col1 Col2 Col3 Col4 Col5 Col6
------ ------- ------- ------- ------- ------- -------
1 ab cd ef gh ij
2 kl mn op qr st null
我正在尝试将逗号分隔的值字符串转换为一个表。这个想法是相同的,只需将分隔符定义为CHAR10而不是逗号,然后删除CHAR13`characters,或者将CHAR10替换为,然后再次删除CHAR13 characters。SQL Server是一种基于集合的语言,您应该使用基于集合的解决方案。我个人推荐一种基于集合的解决方案,例如真正的基于集合的XML拆分器,甚至是CLR函数。@Larnu我对SQL编码还是相当陌生,所以我认为那篇文章的大部分内容都超出了我的理解范围,但这仍然是一本很棒的读物!谢谢你的链接!很高兴你花时间读了它。我很感激这不是入门级的,但是听到有人在这个网站上花时间学习和做进一步的阅读,真是令人耳目一新;你忘了有些是存在的;我正在尝试将逗号分隔的值字符串转换为一个表。这个想法是相同的,只需将分隔符定义为CHAR10而不是逗号,然后删除CHAR13`characters,或者将CHAR10替换为,然后再次删除CHAR13 characters。SQL Server是一种基于集合的语言,您应该使用基于集合的解决方案。我个人推荐一种基于集合的解决方案,例如真正的基于集合的XML拆分器,甚至是CLR函数。@Larnu我对SQL编码还是相当陌生,所以我认为那篇文章的大部分内容都超出了我的理解范围,但这仍然是一本很棒的读物!谢谢你的链接!很高兴你花时间读了它。我很感激这不是入门级的,但是听到有人在这个网站上花时间学习和做进一步的阅读,真是令人耳目一新;你忘了有些是存在的;