T-SQL如何创建比较字符串,检查差异,并执行特殊功能的功能

时间:2017-01-26 19:39:32

标签: sql tsql

首先 - 抱歉我的英语。第二 - 我学习t-SQL。

目标:

我想在两个字符串之间找到区别,然后检查哪个列是这个区别。如果差异在第一列,请执行某些操作,如果在第二列中 - 执行其他操作。

我实际上在做什么

列'消息'是一个包含ID列表的字符串。所以我要取代所有的#'#'与','并删除最后一个','什么给了我 ActualID BeforeID 列。见下文:

DECLARE @string VARCHAR(512);
DECLARE @string2 VARCHAR(512);
DECLARE @string3 VARCHAR(512);

SET @string = '41#42#43#44#45#46#47#48#49#50#51#52#53#54#55#56#57#58#59#';
SET @string2 = REPLACE((SELECT messages FROM USERS WHERE userid = 4), '#', ', ' )
SET @string3 = left(@string2, len(@string2) - 1);
SET @string2 = REPLACE(@string, '#', ', ' )
SET @string = left(@string2, len(@string2) - 1);
SELECT @string3 as ActualID, @string as BeforeID

myquery

现在,我希望将 BeforeID ActualID 进行比较。例如:

在BeforeID中,我们有1, 2, 3 / In ActualID 1, 2, 3, 4

在上面的示例中添加了4。因此,如果添加它,我想将其添加到@AddedElements

如果添加了4, 5, 7,那么SELECT @AddedElements as AddedElements应该返回4, 5, 7(有逗号)

但是,并非全部。

如果 BeforeID = 1, 5, 10, 14 ActualID = 1, 5, 14,我想要的是 BeforeID 中的元素,但不会将 AcutalID 添加到@DeletedElements中。

因此SELECT @DeletedElements as DeletedElements应该返回10

添加元素/已删除的元素应返回一次。我的意思是,我希望获得的完整结果应该是

SELECT @AddedElements as AddedElements, @DeletedElements as DeletedElements

有可能吗?如果,那怎么办?

1 个答案:

答案 0 :(得分:1)

首先,我必须首先说这只是糟糕的设计;但话虽如此,我也发现自己处于各种情况下,我无法改变工作方式,只是试着让它们在当前配置中更好地工作。因此,我建议这样的事情:

1:创建一个UDF(用户定义函数),它可以处理拆分字符串并将它们返回到可以使用的表格数据中:

CREATE FUNCTION [dbo].[UDF_StringDelimiter]
/*********************************************************
**  Takes Parameter "LIST" and transforms it for use    **
**  to select individual values or ranges of values.    **
**                                                      **
**  EX: 'This,is,a,test' = 'This' 'Is' 'A' 'Test'       **
*********************************************************/
    (
          @LIST             VARCHAR(8000)
         ,@DELIMITER        VARCHAR(255)
    )

RETURNS @TABLE TABLE 
    ( 
         [RowID] INT IDENTITY
        ,[Value] VARCHAR(255)
    )
WITH SCHEMABINDING
AS 
BEGIN
    DECLARE 
         @LISTLENGTH AS SMALLINT
        ,@LISTCURSOR AS SMALLINT
        ,@VALUE AS VARCHAR(255)
    ;
    SELECT 
         @LISTLENGTH = LEN(@LIST) - LEN(REPLACE(@LIST,@DELIMITER,'')) + 1
        ,@LISTCURSOR = 1
        ,@VALUE = ''
    ;
    WHILE @LISTCURSOR <= @LISTLENGTH
    BEGIN

        INSERT INTO @TABLE (Value)
        SELECT 
            CASE
                WHEN @LISTCURSOR < @LISTLENGTH
                    THEN SUBSTRING(@LIST,1,PATINDEX('%' + @DELIMITER + '%',@LIST) - 1)
                ELSE SUBSTRING(@LIST,1,LEN(@LIST))
            END
        ;
        SET @LIST = STUFF(@LIST,1,PATINDEX('%' + @DELIMITER + '%',@LIST),'')
        ;       
        SET @LISTCURSOR = @LISTCURSOR + 1
        ;
    END
    ;
    RETURN
    ;
END
;

2:考虑放弃整个“切换逗号”的东西,因为它没有意义 - 我在这里写的函数有两个参数:字符串本身和分隔符(分隔单个字符串的迷你字符串)大字符串,在你的情况下'#')然后你只需要做几个快速比较,找出添加的内容和删除的内容。

DECLARE 
     @AddedElements VARCHAR(255) = ''
    ,@DeletedElements VARCHAR(255) = ''
    ,@ActualID VARCHAR(255) = '41#42#43#44#45#46#47#48#49#50#51#52#53#54#55#56#57#58#59#'
    ,@BeforeID VARCHAR(255) = '41#42#43#44#45#46#47#48#50#51#52#53#54#55#56#57#58#59#60#'
;

SET @AddedElements = @AddedElements + 
    SUBSTRING(
        (
        SELECT ', ' + Value
        FROM dbo.UDF_StringDelimiter(@ActualID,'#')
        WHERE Value NOT IN
            (
            SELECT Value
            FROM dbo.UDF_StringDelimiter(@BeforeID,'#')
            )
        GROUP BY ', ' + Value
        FOR XML PATH('')
        )
    ,3,255)
;

SET @DeletedElements = @DeletedElements + 
    SUBSTRING(
        (
        SELECT ', ' + Value
        FROM dbo.UDF_StringDelimiter(@BeforeID,'#')
        WHERE Value NOT IN
            (
            SELECT Value
            FROM dbo.UDF_StringDelimiter(@ActualID,'#')
            )
        GROUP BY ', ' + Value
        FOR XML PATH('')
        )
    ,3,255)
;

SELECT @AddedElements AS AddedElements,@DeletedElements AS DeletedElements
;

使用此方法,如果您向@ActualID添加@BeforeID中不存在的值,它将显示在@AddedElements中。

同样,如果您从先前@ActualID中存在的@BeforeID中删除了一个元素,它将显示在@DeletedElements中。

当然,所有这些都假设动态字符串(这里真正比较的那个)是@ActualID。我操作时理解@BeforeID实际上是DB中的存储值,而@ActualID是从某个地方传入的动态字符串。如果这是错误的,请更新我,我会适当地改变策略。

快速说明:对我来说,重要的是要指出这只是处理这种情况的一种方式,而且我确信有更好的方法;但是根据我所拥有的信息,这是我能想到的最好的,而不会花太多时间和精力。