通过删除大括号中的文本来更新列
Update column by removing text in braces
我需要更新 table 中所有行的单列。更新应该以这样的方式进行,即需要通过删除所有为字符串附加大括号的文本并交换由 ','
.
分隔的字符串来过滤掉数据
示例:
Column A
---------
Ab,cde(123)
Ab,cde
yz,kol
yz,kol(567)
uv,xyz
first name,lastname (123456)
按照上面的例子,我需要最终的数据是这样的
Output
---------
cde, Ab
cde, Ab
kol, yz
kol, yz
xyz,uv
lastname,first name
请告诉我如何在 SQL 服务器中实现上述输出。
试试这个 SQL 代码:
;WITH cte
AS (
SELECT ColumnA AS [Column1]
,CASE
WHEN charindex('(', ColumnA) > 0
AND charindex(')', ColumnA) > charindex('(', ColumnA)
THEN stuff(ColumnA, charindex('(', ColumnA), charindex(')', ColumnA) - charindex('(', ColumnA) + 1, '')
ELSE ColumnA
END AS [Column2]
,0 AS [Level] FROM t1
)
,cte1
AS (
SELECT *
,row_number() OVER (
PARTITION BY [Column1] ORDER BY [Level] DESC
) AS Rn
FROM cte
)
SELECT Column1, Column2 ,
REPLACE( REPLACE(cte1.Column2 , SUBSTRING(Column2 , 0 , CHARINDEX(N',' , Column2)) , N'') , N',' , N'') + N', ' + SUBSTRING(Column2 , 0 , CHARINDEX(N',' , Column2)) AS OutPut
FROM cte1 where Rn = 1
如果您理解如何正确Cascade APPLY,这就很容易了。请注意示例数据和解决方案。
--==== Sample Data
DECLARE @table TABLE (ColA VARCHAR(100));
INSERT @table VALUES ('Ab,cde(123)'),('Ab,cde'),('yz,kol'),('yz,kol(567)'),('uv,xyz');
--==== Solution
SELECT
[Output] = CONCAT(SUBSTRING(f.String,f2.Pos+1,8000),', ',SUBSTRING(f.String,1,f2.Pos-1))
FROM @table AS t
CROSS APPLY (VALUES(ISNULL(NULLIF(CHARINDEX('(',t.ColA),0),LEN(t.ColA)+1))) AS st(Pos)
CROSS APPLY (VALUES(SUBSTRING(t.ColA,1,st.Pos-1))) AS f(String)
CROSS APPLY (VALUES(CHARINDEX(',',f.String))) AS f2(Pos);
Returns:
Output
-----------------------
cde, Ab
cde, Ab
kol, yz
kol, yz
xyz, uv
更新 20210716
对于那些想知道为什么这个解决方案快得多的人来说,这与本例中 APPLY, Cascading APPLY 的魔力有关。
首先让我们运行查询并比较执行计划:
APPLY 解决方案需要单个标量运算符才能完成工作。另一种方法需要一个段和序列运算符来生成 ROW_NUMBER ,它被排序和过滤。
请注意,计划中 % 的 26% 用于 table 变量。
性能测试:
--==== Sample Data
DECLARE @table TABLE (ColA VARCHAR(100));
INSERT @table VALUES ('Ab,cde(123)'),('Ab,cde'),('yz,kol'),('yz,kol(567)'),('uv,xyz');
;WITH cte
AS (
SELECT t.ColA AS [Column1]
,CASE
WHEN charindex('(', t.ColA) > 0
AND charindex(')', t.ColA) > charindex('(', t.ColA)
THEN stuff(t.ColA, charindex('(', t.ColA), charindex(')', t.ColA) - charindex('(', t.ColA) + 1, '')
ELSE t.ColA
END AS [Column2]
,0 AS [Level] FROM @table AS t
)
,cte1
AS (
SELECT *
,row_number() OVER (
PARTITION BY [Column1] ORDER BY [Level] DESC
) AS Rn
FROM cte
)
SELECT Column1, Column2 ,
REPLACE( REPLACE(cte1.Column2 , SUBSTRING(Column2 , 0 , CHARINDEX(N',' , Column2)) , N'') , N',' , N'') + N', ' + SUBSTRING(Column2 , 0 , CHARINDEX(N',' , Column2)) AS OutPut
FROM cte1 where Rn = 1
SELECT
[Output] = CONCAT(SUBSTRING(f.String,f2.Pos+1,8000),', ',SUBSTRING(f.String,1,f2.Pos-1))
FROM @table AS t
CROSS APPLY (VALUES(ISNULL(NULLIF(CHARINDEX('(',t.ColA),0),LEN(t.ColA)+1))) AS st(Pos)
CROSS APPLY (VALUES(SUBSTRING(t.ColA,1,st.Pos-1))) AS f(String)
CROSS APPLY (VALUES(CHARINDEX(',',f.String))) AS f2(Pos);
GO
-- Test Harness;
IF OBJECT_ID('tempdb..#table','U') IS NOT NULL DROP TABLE #table;
CREATE TABLE #table (ColA VARCHAR(100));
INSERT #table
SELECT TOP (1000000) f.X
FROM (VALUES(REPLACE(LEFT(NEWID(),12),'-',',')+'(xxx)'),
(REPLACE(LEFT(NEWID(),12),'-',','))) AS f(X)
CROSS JOIN sys.all_columns, sys.all_columns AS b;
--==== Run the test
DECLARE @x VARCHAR(100);
SET STATISTICS TIME ON;
;WITH cte
AS (
SELECT t.ColA AS [Column1]
,CASE
WHEN charindex('(', t.ColA) > 0
AND charindex(')', t.ColA) > charindex('(', t.ColA)
THEN stuff(t.ColA, charindex('(', t.ColA), charindex(')', t.ColA) - charindex('(', t.ColA) + 1, '')
ELSE t.ColA
END AS [Column2]
,0 AS [Level] FROM #table AS t
)
,cte1
AS (
SELECT *
,row_number() OVER (
PARTITION BY [Column1] ORDER BY [Level] DESC
) AS Rn
FROM cte
)
SELECT @x =
REPLACE( REPLACE(cte1.Column2 , SUBSTRING(Column2 , 0 , CHARINDEX(N',' , Column2)) , N'') , N',' , N'') + N', ' + SUBSTRING(Column2 , 0 , CHARINDEX(N',' , Column2))
FROM cte1
where Rn = 1
SELECT @x = CONCAT(SUBSTRING(f.String,f2.Pos+1,8000),', ',SUBSTRING(f.String,1,f2.Pos-1))
FROM #table AS t
CROSS APPLY (VALUES(ISNULL(NULLIF(CHARINDEX('(',t.ColA),0),LEN(t.ColA)+1))) AS st(Pos)
CROSS APPLY (VALUES(SUBSTRING(t.ColA,1,st.Pos-1))) AS f(String)
CROSS APPLY (VALUES(CHARINDEX(',',f.String))) AS f2(Pos)
SET STATISTICS TIME, IO OFF;
测试结果:
SQL Server Execution Times: CPU time = 3938 ms, elapsed time = 3935 ms.
SQL Server Execution Times: CPU time = 3422 ms, elapsed time = 3420 ms.
适度的 15% 改进,我期望更好,但是 APPLY 解决方案显然更快。
我需要更新 table 中所有行的单列。更新应该以这样的方式进行,即需要通过删除所有为字符串附加大括号的文本并交换由 ','
.
示例:
Column A
---------
Ab,cde(123)
Ab,cde
yz,kol
yz,kol(567)
uv,xyz
first name,lastname (123456)
按照上面的例子,我需要最终的数据是这样的
Output
---------
cde, Ab
cde, Ab
kol, yz
kol, yz
xyz,uv
lastname,first name
请告诉我如何在 SQL 服务器中实现上述输出。
试试这个 SQL 代码:
;WITH cte
AS (
SELECT ColumnA AS [Column1]
,CASE
WHEN charindex('(', ColumnA) > 0
AND charindex(')', ColumnA) > charindex('(', ColumnA)
THEN stuff(ColumnA, charindex('(', ColumnA), charindex(')', ColumnA) - charindex('(', ColumnA) + 1, '')
ELSE ColumnA
END AS [Column2]
,0 AS [Level] FROM t1
)
,cte1
AS (
SELECT *
,row_number() OVER (
PARTITION BY [Column1] ORDER BY [Level] DESC
) AS Rn
FROM cte
)
SELECT Column1, Column2 ,
REPLACE( REPLACE(cte1.Column2 , SUBSTRING(Column2 , 0 , CHARINDEX(N',' , Column2)) , N'') , N',' , N'') + N', ' + SUBSTRING(Column2 , 0 , CHARINDEX(N',' , Column2)) AS OutPut
FROM cte1 where Rn = 1
如果您理解如何正确Cascade APPLY,这就很容易了。请注意示例数据和解决方案。
--==== Sample Data
DECLARE @table TABLE (ColA VARCHAR(100));
INSERT @table VALUES ('Ab,cde(123)'),('Ab,cde'),('yz,kol'),('yz,kol(567)'),('uv,xyz');
--==== Solution
SELECT
[Output] = CONCAT(SUBSTRING(f.String,f2.Pos+1,8000),', ',SUBSTRING(f.String,1,f2.Pos-1))
FROM @table AS t
CROSS APPLY (VALUES(ISNULL(NULLIF(CHARINDEX('(',t.ColA),0),LEN(t.ColA)+1))) AS st(Pos)
CROSS APPLY (VALUES(SUBSTRING(t.ColA,1,st.Pos-1))) AS f(String)
CROSS APPLY (VALUES(CHARINDEX(',',f.String))) AS f2(Pos);
Returns:
Output
-----------------------
cde, Ab
cde, Ab
kol, yz
kol, yz
xyz, uv
更新 20210716
对于那些想知道为什么这个解决方案快得多的人来说,这与本例中 APPLY, Cascading APPLY 的魔力有关。 首先让我们运行查询并比较执行计划:
APPLY 解决方案需要单个标量运算符才能完成工作。另一种方法需要一个段和序列运算符来生成 ROW_NUMBER ,它被排序和过滤。 请注意,计划中 % 的 26% 用于 table 变量。
性能测试:
--==== Sample Data
DECLARE @table TABLE (ColA VARCHAR(100));
INSERT @table VALUES ('Ab,cde(123)'),('Ab,cde'),('yz,kol'),('yz,kol(567)'),('uv,xyz');
;WITH cte
AS (
SELECT t.ColA AS [Column1]
,CASE
WHEN charindex('(', t.ColA) > 0
AND charindex(')', t.ColA) > charindex('(', t.ColA)
THEN stuff(t.ColA, charindex('(', t.ColA), charindex(')', t.ColA) - charindex('(', t.ColA) + 1, '')
ELSE t.ColA
END AS [Column2]
,0 AS [Level] FROM @table AS t
)
,cte1
AS (
SELECT *
,row_number() OVER (
PARTITION BY [Column1] ORDER BY [Level] DESC
) AS Rn
FROM cte
)
SELECT Column1, Column2 ,
REPLACE( REPLACE(cte1.Column2 , SUBSTRING(Column2 , 0 , CHARINDEX(N',' , Column2)) , N'') , N',' , N'') + N', ' + SUBSTRING(Column2 , 0 , CHARINDEX(N',' , Column2)) AS OutPut
FROM cte1 where Rn = 1
SELECT
[Output] = CONCAT(SUBSTRING(f.String,f2.Pos+1,8000),', ',SUBSTRING(f.String,1,f2.Pos-1))
FROM @table AS t
CROSS APPLY (VALUES(ISNULL(NULLIF(CHARINDEX('(',t.ColA),0),LEN(t.ColA)+1))) AS st(Pos)
CROSS APPLY (VALUES(SUBSTRING(t.ColA,1,st.Pos-1))) AS f(String)
CROSS APPLY (VALUES(CHARINDEX(',',f.String))) AS f2(Pos);
GO
-- Test Harness;
IF OBJECT_ID('tempdb..#table','U') IS NOT NULL DROP TABLE #table;
CREATE TABLE #table (ColA VARCHAR(100));
INSERT #table
SELECT TOP (1000000) f.X
FROM (VALUES(REPLACE(LEFT(NEWID(),12),'-',',')+'(xxx)'),
(REPLACE(LEFT(NEWID(),12),'-',','))) AS f(X)
CROSS JOIN sys.all_columns, sys.all_columns AS b;
--==== Run the test
DECLARE @x VARCHAR(100);
SET STATISTICS TIME ON;
;WITH cte
AS (
SELECT t.ColA AS [Column1]
,CASE
WHEN charindex('(', t.ColA) > 0
AND charindex(')', t.ColA) > charindex('(', t.ColA)
THEN stuff(t.ColA, charindex('(', t.ColA), charindex(')', t.ColA) - charindex('(', t.ColA) + 1, '')
ELSE t.ColA
END AS [Column2]
,0 AS [Level] FROM #table AS t
)
,cte1
AS (
SELECT *
,row_number() OVER (
PARTITION BY [Column1] ORDER BY [Level] DESC
) AS Rn
FROM cte
)
SELECT @x =
REPLACE( REPLACE(cte1.Column2 , SUBSTRING(Column2 , 0 , CHARINDEX(N',' , Column2)) , N'') , N',' , N'') + N', ' + SUBSTRING(Column2 , 0 , CHARINDEX(N',' , Column2))
FROM cte1
where Rn = 1
SELECT @x = CONCAT(SUBSTRING(f.String,f2.Pos+1,8000),', ',SUBSTRING(f.String,1,f2.Pos-1))
FROM #table AS t
CROSS APPLY (VALUES(ISNULL(NULLIF(CHARINDEX('(',t.ColA),0),LEN(t.ColA)+1))) AS st(Pos)
CROSS APPLY (VALUES(SUBSTRING(t.ColA,1,st.Pos-1))) AS f(String)
CROSS APPLY (VALUES(CHARINDEX(',',f.String))) AS f2(Pos)
SET STATISTICS TIME, IO OFF;
测试结果:
SQL Server Execution Times: CPU time = 3938 ms, elapsed time = 3935 ms.
SQL Server Execution Times: CPU time = 3422 ms, elapsed time = 3420 ms.
适度的 15% 改进,我期望更好,但是 APPLY 解决方案显然更快。