T-SQL根据另一个表列过滤一列上的多个值

时间:2015-12-16 16:51:31

标签: sql-server database contains

请帮忙。

我正在使用SQL Server并熟悉CONTAINS关键字。

我有一张桌子"表1"列值如

1,'bla1 bla2 bla3 String1 bla4 bla5 bla6 String2 bla7 bla8 bla9'
2,'bla3 String1 bla4 String2 bla7 bla8 bla1'
3,'bla3 String2 bla4 String3'

我有另一张桌子"表2"只有一列,但有动态值,如

1,bla1
2,string1
3,bla3

1,string2
2,bla5
3,bla1
4,bla4

我只想根据表2中的所有值返回Table1中的行,表示它不是OR,而是AND - Table2中的所有值都应该出现在表1和#中39; s列值(可以按任何顺序)。

在上面的例子中,

  • 如果针对Table1检查了Table2的第一个集合,那么它应该只返回Table1中的前两行
  • 如果Table2的第二组是针对Table1检查的,那么它应该只返回Table1的第一行

,表1中的某个值在表1的列值中不可用。

由于这两个表都是临时表变量,我无法在其上添加FULL-TEXT INDEX,否则我可以使用 CONTAINS(Column, 'SearchString1 AND SearchString2 AND SearchString3 AND so on')

以下代码可以正常工作,但最多只能搜索2个字符串。超过2,它不工作。例如,如果我在下面的代码中有这样的话

declare @str nvarchar(100) = ' Dr clark Nick '
DECLARE @Tab TABLE(Col NVARCHAR(50))
INSERT INTO @Tab
SELECT ' Dr. Nick Clark' UNION ALL
SELECT ' Dr. Nick SPACE Clark' UNION ALL
SELECT ' Dr. Clark SPACE Nick' UNION ALL
SELECT ' Dr. Clark Nick' UNION ALL
SELECT ' Dr. Nick' UNION ALL
SELECT ' Dr. Clark '

declare @str nvarchar(100) = '  Nick clark '

set @str = ltrim(rtrim(@str))

DECLARE @Search1 VARCHAR(MAX), @Search2 VARCHAR(MAX) 

declare @t table(sno int, splitdata nvarchar(100))
insert into @t
SELECT 
    row_number() over (order by ltrim(rtrim(o.splitdata))) as sno,
    ltrim(rtrim(o.splitdata)) AS splitdata
FROM
    (SELECT CAST('<X>'+REPLACE(@str,' ','</X><X>')+'</X>' AS XML) AS Filter)F1
     CROSS APPLY
          ( SELECT fdata.D.value('.','varchar(MAX)') AS splitdata 
          FROM f1.Filter.nodes('X') AS fdata(D)
    ) O

SELECT @Search1 = COALESCE(@Search1 + '%', '') + Splitdata FROM @t order by sno
SELECT @Search2 = COALESCE(@Search2 + '%', '') + Splitdata FROM @t order by sno desc

select * from @tab where col like '%'+@Search1+'%' or col like '%'+@Search2+'%'

1 个答案:

答案 0 :(得分:0)

set nocount on;

declare @Tab table (col nvarchar(50));

insert @Tab (Col)
values (' Dr. Nick Clark')
     , (' Dr. Nick SPACE Clark')
     , (' Dr. Clark SPACE Nick')
     , (' Dr. Clark Nick')
     , (' Dr. Nick')
     , (' Dr. Clark ');

declare @str nvarchar(100) = '  Nick clark ';
set @str = ' ' + ltrim(rtrim(@str)) + ' ';

with Tally
as (
    select row_number() over (order by t1.column_id) as 'N'
      from sys.columns t1
      join sys.columns t2
        on 1=1
   )
, Needles
as (
    select substring(@str,N+1,charindex(' ',@str,N+1)-N-1) 'Needle'
      from Tally
     where N < len(@str)
       and substring(@str,N,1) = ' '
   )
, NotSelected
as (
    select tab.col
      from @tab tab
      join Needles
        on 1=1
     where charindex(Needles.Needle,tab.col) = 0
   )
   select Tab.Col
     from @Tab Tab
left join NotSelected
       on NotSelected.Col = Tab.Col
    where NotSelected.Col is null;

好的,所以这是我的方法:我们将您的搜索字符串转换为记录集,以空格分隔。我使用Tally-table方法,但是使用基于sys.columns的Common Table Expression而不是Real tally表...基本上给了一个完整的表,我可以使用它来快速分离你的空间 - 将字符串分隔成记录集。我称之为Needles,因为我们正在@tab haystack中寻找这些针。

我创建了针和干草堆的笛卡尔记录集以及CHARINDEXneedle的第一个位置的haystack值。任何零值都告诉我针头不在大海捞针中。这也是一个名为“NotSelected”的常见表格表达式 - 现在列出了找不到针头的所有@Tab.Col值。

最后,Not Selected行与完整表的左连接将显示所有与Not Selected值不匹配的记录。