2017-10-09 41 views
0

如何替换特殊字符之间的缺少字符串与其他列相同位置特殊字符字符串在SQL中?下面是例子如何替换在sql中具有相同位置的其他列值的特殊字符?

如:

ColumnA    columnB  Output of columnb 
~as~df~gf~er   ~qw~~~   ~qw~df~gf~er 
~Evening~Afternoon  ~~    ~Evening~Afternoon 
~qw~dg~er~rt~yu~io~ty ~df~~rt~~we~~ ~df~dg~rt~rt~we~io~ty 

提示:这列特殊字符数将是相同的。 我需要这样的列输出〜qw〜df〜gf〜er。
我想动态改变所有缺少特殊字符的字符串。请在此帮助我

+0

这是你的更新规则,这很不清楚吗? –

+0

在哪个位置数据应该被替换或更新? –

+0

如果在特殊字符之间缺少字符串,我们需要将columnA字符串替换为相同的位置。而columnb需要更新columnb(这是我需要在columnb中更新的方式) – Malyadri

回答

0

您需要正确的功能,并且可以轻松解决。例如,在我的数据库,我有:

DECLARE @DataSource TABLE 
( 
    [ColumnA] VARCHAR(1024) 
    ,[ColumnB] VARCHAR(1024) 
); 

INSERT INTO @DataSource ([ColumnA], [ColumnB]) 
VALUES ('~as~df~gf~er', '~qw~~~') 
     ,('~Evening~Afternoon', '~~') 
     ,('~qw~dg~er~rt~yu~io~ty', '~df~~rt~~we~~'); 


SELECT DS.[ColumnA] 
     ,DS.[ColumnB] 
     ,[dbo].[ConcatenateWithOrderAndDelimiter] (A.[index], ISNULL(NULLIF(B.[value], ''), A.[value]), '~') 
FROM @DataSource DS 
CROSS APPLY [dbo].[fn_Utils_RegexSplitWithOrder] ([ColumnA], '~') A 
LEFT JOIN 
(
    SELECT [ColumnA] 
      ,B.[index] 
      ,B.[value] 
    FROM @DataSource DS 
    CROSS APPLY [dbo].[fn_Utils_RegexSplitWithOrder] ([ColumnB], '~') B 
) B 
    ON DS.[ColumnA] = B.[ColumnA] 
    AND A.[index] = B.[index] 
GROUP BY DS.[ColumnA] 
     ,DS.[ColumnB]; 

enter image description here

所以,基本上需要两个功能:

  1. 一个由价值
  2. 一个分割字符串字符串聚集(串联)

在我的情况我使用SQL CLR的乐趣ction - 你可以找到更多关于他们here

在SQL Server 2017中,我们可以使用STRING_AGG,而从SQL Server 2016我们可以使用STRING_SPIT

如果你不想浪费时间来实现SQL CLR函数,你可以添加一个拆分函数(网络中有很多)。例如,我用这一个:

CREATE FUNCTION [dbo].[fn_Analysis_ConvertCsvListToNVarCharTableWithOrder](@List nvarchar(max), @Delimiter nvarchar(10) = ',') 
RETURNS @result TABLE 
( 
    [Value] nvarchar(max), 
    [SortOrder] bigint NOT NULL 
) 
AS 
BEGIN 
    IF @Delimiter is null 
    BEGIN 
     SET @Delimiter = ',' 
    END 
    DECLARE @XML xml = N'<r><![CDATA[' + REPLACE(@List, @Delimiter, ']]></r><r><![CDATA[') + ']]></r>' 

    DECLARE @BufTable TABLE (Value nvarchar(max), SortOrder bigint NOT NULL IDENTITY(1, 1) PRIMARY KEY) 
    INSERT INTO @BufTable (Value) 
     SELECT Tbl.Col.value('.', 'nvarchar(max)') 
     FROM @xml.nodes('//r') Tbl(Col) 
     OPTION (OPTIMIZE FOR (@xml = NULL)) 

    INSERT INTO @result (Value, SortOrder) 
     SELECT Value, SortOrder 
     FROM @BufTable 

    RETURN 
END 

,这应该会给你想你想:

WITH DataSource AS 
(
    SELECT DS.[ColumnA] 
      ,DS.[ColumnB] 
      ,A.[SortOrder] 
      ,ISNULL(NULLIF(B.[value], ''), A.[Value]) AS [Value] 
    FROM @DataSource DS 
    CROSS APPLY [dbo].[fn_Analysis_ConvertCsvListToNVarCharTableWithOrder] (REPLACE([ColumnA], ',', '~'), '~') A 
    LEFT JOIN 
    (
     SELECT [ColumnA] 
       ,B.[SortOrder] 
       ,B.[value] 
     FROM @DataSource DS 
     CROSS APPLY [dbo].[fn_Analysis_ConvertCsvListToNVarCharTableWithOrder] (REPLACE([ColumnB], ',', '~'), '~') B 
    ) B 
     ON DS.[ColumnA] = B.[ColumnA] 
     AND A.[SortOrder] = B.[SortOrder] 
) 
SELECT DISTINCT A.[ColumnA] 
       ,A.[ColumnB] 
       ,DS.[value] 
FROM DataSource A 
CROSS APPLY 
(
    SELECT STUFF 
    (
     (
      SELECT '~' + B.[Value] 
      FROM DataSource B 
      WHERE A.[ColumnA] = B.[ColumnA] 
      ORDER BY B.[SortOrder] 
      FOR XML PATH(''), TYPE 
     ).value('.', 'VARCHAR(MAX)') 
     ,1 
     ,1 
     ,'' 
    ) 
) DS ([value]); 
0

你可以尝试,而无需创建Function(): -

DECLARE @ColumnA NVARCHAR(MAX); 
DECLARE @columnB NVARCHAR(MAX); 

SET @ColumnA = '~as~df~gf~er '; 
SET @columnB = ' ~qw~~~'; 

;WITH CTE 
    AS (
    SELECT Split.a.value('.', 'NVARCHAR(MAX)') DATA, 
      ROW_NUMBER() OVER(ORDER BY @ColumnA) RN 
    FROM 
    (
     SELECT CAST('<M>'+REPLACE(@ColumnA, '~', '</M><M>')+'</M>' AS XML) AS String 
    ) AS A 
    CROSS APPLY String.nodes('/M') AS Split(a)), 
    CTE1 
    AS (
    SELECT Split.a.value('.', 'NVARCHAR(MAX)') DATA1, 
      ROW_NUMBER() OVER(ORDER BY @columnB) RN 
    FROM 
    (
     SELECT CAST('<M>'+REPLACE(@columnB, '~', '</M><M>')+'</M>' AS XML) AS String 
    ) AS A 
    CROSS APPLY String.nodes('/M') AS Split(a)) 
    SELECT @ColumnA AS ColumnA, 
      @columnB AS columnB, 
      [Output of columnb] = 
    (
     SELECT '~'+CASE 
         WHEN C1.DATA1 = '' 
         THEN C2.DATA 
         ELSE C1.DATA1 
        END 
     FROM CTE1 C1 
       INNER JOIN CTE C2 ON C2.RN = C1.RN 
            AND C1.RN > 1 FOR XML PATH('') 
    ); 

期望输出:

ColumnA    columnB  Output of columnb 
~as~df~gf~er   ~qw~~~   ~qw~df~gf~er