【问题标题】:Search if a string word exists between two different tables in a comma-delimited field搜索逗号分隔字段中两个不同表之间是否存在字符串词
【发布时间】:2009-11-21 18:58:02
【问题描述】:

我有两张桌子:

EmployeeTypeA 表
名称 varchar(2000) 字段包含 - 'john,sam,doug'

EmployeeTypeB 表
名称 varchar(2000) 字段包含 - 'eric,sam,allen,stephanie'

当使用 MS SQL 在两个列表中都找到一个名称时,返回真或假的最有效方法是什么?这需要在存储过程中完成,因此我不能使用编程语言在 SQL 之外对其进行操作。在这个例子中,因为 'sam' 在两个表中,我想返回一个 true(或 0 等)

我应该先将逗号分隔的字段分开,然后将项目放在临时表中吗?还是使用游标?

谢谢

【问题讨论】:

    标签: sql sql-server tsql


    【解决方案1】:

    首先将逗号分隔的字段分隔到临时表或表变量中。这样,您可以准确地连接或匹配行。为每个名称创建一行,并包含某种有助于关联行的关键列。

    最好的方法是使用这样的“帮助表”:

    DECLARE @numbers TABLE (number int)
    DECLARE @i int 
    SET @i = 1
    WHILE (@i < 1001)
    BEGIN    
    INSERT INTO @numbers (number) VALUES (@i)    
    SET @i = @i+1
    END
    
    
    DECLARE @TestString VARCHAR(200)
    SET @TestString = 'andy,john,mark'
    DECLARE @RowDelimiter VARCHAR(1)
    SET @RowDelimiter=','
    
    SELECT SUBSTRING(@TestString+@RowDelimiter, number, 
        CHARINDEX(@RowDelimiter, @TestString+@RowDelimiter, number) - number) 
    FROM @numbers 
    WHERE number <= LEN(@TestString) 
    AND SUBSTRING(@RowDelimiter+ @TestString, number, 1) = @RowDelimiter
    ORDER BY number 
    -- helper table technique: bill@creaticle.com
    

    结果是:

    andy
    john
    mark
    

    一旦你有两个临时表,然后做一个 FULL OUTER JOIN 并在你的“found in both”列中包含一个设置值。您将获得两者中均未找到的名称的 NULL 值 - 您可以将 NULL 视为“False”值。

    您能否提及为什么需要为两个表之间的匹配获取布尔值?接下来你打算用它做什么?有时解释这将导致更好的解决方案。你可能会发现你在仓促地做出假设。最好的,比尔。

    【讨论】:

    • 嗨,比尔。你能给一些完整的外部连接的代码吗?我不知道它是如何工作的。
    • 是的。代码不会出现在这个评论中,所以我会再发一个回复并标记为第 2 部分。
    • 或者更好的是,修复设计并将它们分开到永久表中,然后继续使用。数据字段不应该存储逗号分隔的列表。这表明需要相关表。
    【解决方案2】:

    未经测试:

    SELECT COUNT(*) FROM EmployeeTypeA 
     WHERE ',' + nameListField + ',' LIKE '%,' + @searchedName + ',%'
    

    如果名称已在第一个表的列表中找到,则应返回某个值 &gt; 0。对第二个表执行相同操作,如果两个 SELECT 都返回非零值,则返回 true。

    PS:如果您有权更改数据库设计:请执行此操作。规范化的数据库不应包含逗号分隔的列表,而应包含具有外键关系的子表。

    【讨论】:

    • 看起来它应该可以工作,虽然我可以理解 MS SQL 对 like 左侧复杂性的理解。
    【解决方案3】:

    这是一个脚本,它创建两个测试表,如果名称在两个表中,则返回带有“True”的名称列表。它通过使用左连接来查找两个表中或仅在表 A 中的名称。此结果集联合到右连接以获取仅在表 B 中的名称。

    DROP TABLE EmployeeTypeA
    DROP TABLE EmployeeTypeB
    GO
    
    CREATE TABLE EmployeeTypeA
        (Name VARCHAR(2000))
    GO
    
    CREATE TABLE EmployeeTypeB
        (Name VARCHAR(2000))
    GO
    
    INSERT INTO EmployeeTypeA VALUES ('john')
    INSERT INTO EmployeeTypeA VALUES ('sam')
    INSERT INTO EmployeeTypeA VALUES ('doug')
    
    INSERT INTO EmployeeTypeB VALUES ('eric')
    INSERT INTO EmployeeTypeB VALUES ('sam')
    INSERT INTO EmployeeTypeB VALUES ('allen')
    INSERT INTO EmployeeTypeB VALUES ('stephanie')
    GO
    
    SELECT
        eta.Name,
        CASE
            WHEN etb.Name IS NULL THEN 'False'
            ELSE 'True'
        END
    FROM
        EmployeeTypeA eta
        LEFT JOIN EmployeeTypeB etb ON
            eta.Name = etb.Name
    
    UNION
    
    SELECT
        etb.Name,
        'False'
    FROM
        EmployeeTypeA eta
        RIGHT JOIN EmployeeTypeB etb ON
            eta.Name = etb.Name
    WHERE
        eta.Name IS NULL
    
    GO
    

    【讨论】:

      【解决方案4】:

      这是我上面的第 2 部分,因此我可以添加其他代码。这部分解释了如何在将您的姓名撕成单独的行之后获取表之间是否存在匹配的布尔值。

      DECLARE @LeftTable TABLE (thisid int, thisname varchar(50))
      
      INSERT INTO @LeftTable VALUES  (1, 'andy')
      INSERT INTO @LeftTable VALUES  (2, 'bill')
      INSERT INTO @LeftTable VALUES  (3, 'zed')
      
      DECLARE @RightTable TABLE (thisid int, thisname varchar(50))
      
      INSERT INTO @RightTable VALUES  (1, 'chris')
      INSERT INTO @RightTable VALUES  (2, 'bill')
      INSERT INTO @RightTable VALUES  (3, 'zed')
      
      SELECT 
      a.thisname AS theleftname, 
      b.thisname AS therightname, 
      CASE
          WHEN (ISNULL(a.thisname,'') = '' OR ISNULL(b.thisname,'') = '') THEN 'False'
          ELSE 'True'
      END     
      AS namematches
      FROM @LeftTable a
      FULL OUTER JOIN @RightTable b
      ON a.thisname = b.thisname
      -- www.caliberwebgroup.com
      

      结果如下:

      theleftname therightname    namematches 
      NULL    chris   False
      bill    bill    True
      zed     zed     True
      andy    NULL    False
      

      【讨论】:

        【解决方案5】:

        您可以编写一个表值函数,它接受一个逗号分隔的字符串并返回一个字符串表(一列)。

        Create FUNCTION [dbo].[SplitStrings]
        (
            @StringList varchar(max)
        )
        RETURNS 
        @Outputable table
        (
            ParsedItem varchar(2000)
        )
        
        as
        
        -- you can have a while loop here to populate the table.
        

        这也将使您的代码可重复使用。 但是请记住,如果您使用很多行,这可能会成为性能瓶颈。它会为每一行运行。

        已更新!!!

        是的,一旦获得表格,您就可以使用其他答案的连接。

        【讨论】:

          【解决方案6】:

          试试这个

          declare @EmployeeTypeA table(Name VARCHAR(2000))
          insert into @EmployeeTypeA select 'john,sam,doug'
          declare @EmployeeTypeB table(Name VARCHAR(2000))
          insert into @EmployeeTypeB select  'eric,sam,allen,stephanie'
          

          --程序开始

          declare @xA xml
          declare @xB xml
          select @xA = '<i>' + REPLACE(Name, ',', '</i><i>') + '</i>'  from @EmployeeTypeA
          select @xB = '<i>' + REPLACE(Name, ',', '</i><i>') + '</i>'  from @EmployeeTypeB
          
          select 
           EmployeeTypeA
           ,EmployeeTypeB     
          
          from (
          SELECT 
            EmployeeTypeA
            ,i.value('.', 'VARCHAR(MAX)') EmployeeTypeB
            FROM @xB.nodes('//i') x(i)
            cross apply(
            SELECT i.value('.', 'VARCHAR(MAX)') EmployeeTypeA
            FROM @xA.nodes('//i') x(i)) Y) Res(EmployeeTypeA,EmployeeTypeB)
            where EmployeeTypeA = EmployeeTypeB
          

          输出:

          EmployeeTypeA EmployeeTypeB

          sam             sam
          

          【讨论】:

            猜你喜欢
            • 2016-04-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-05-29
            • 1970-01-01
            • 2016-08-30
            相关资源
            最近更新 更多