SQL 服务器:基于 2 列查找集合的最有效方法

SQL Server: Most efficient way to look for set based on 2 columns

编辑: 我意识到我问错了问题。我真正想问的是,"given a set of values for [Column B], check if there is a value in [Column A] that matches all of the set and no others."


我不确定我想做的事情是否有正式名称,所以很难搜索我的问题。

给定一个包含 2 列和一个值列表的 table,我想看看 table.

中是否存在这个组合(并且只有这个组合)

例如,给定这个 table(假设它是整个 table):

|----------|----------|
| Column A | Column B |
|----------|----------|
| 12345    | abcde    |
|----------|----------|
| 12345    | xyz      |
|----------|----------|
| 12345    | abcd     |
|----------|----------|
| 12345    | abbba    |
|----------|----------|

并给定此输入参数:

Declare @columnBs Varchar(Max) = '["abcde","xyz","abcd","abbba"]';

对于那个集合,我想要 return 12345。所以,基本上,我想 运行 检查并查看 [Column A] 中的任何值是否与 [Column B] 中的所有值匹配 @columnBs [=41] 中的所有值=]并且没有其他值。

如果没有 [Column A] 的值作为起点,我什至无法构思一个长格式的解决方案。


如果有助于更好地概念化,这是一个消息传递解决方案,其中:

因此,如果收到一组用户的新消息,我想查看是否存在针对 @columnBs 提供的所有用户的现有线程,而没有其他用户。

如果您使用 SQL Server 2016 及更高版本,请使用 STRING_SPLIT()。如果您使用早期版本的 SQL 服务器,您可以使用此 http://www.sqlservercentral.com/articles/Tally+Table/72993/ 将 CSV 解析为列式结果列表

declare @table table
(
    ColumnA int,
    ColumnB varchar(6)
)

insert into @table select 12345, 'abcde'
insert into @table select 12345, 'xyz'
insert into @table select 12345, 'abcd'
insert into @table select 12345, 'abbba'

declare @columnBs varchar(max) = 'abcde,xyz,abcd,abbba';

; with cte as
(
    select  value, cnt = count(*) over()
    from    string_split(@columnBs, ',')
)
select  ColumnA
from    cte c
    inner join @table t on  c.value = t.ColumnB
group by ColumnA
having count(*) = max(c.cnt)

我读到您需要在 ColumnA 中找到一个值,该值与查询中的相同值完全一致,不多也不少。因此,您需要加入搜索值,确保它们都存在于单个 ColumnA 中,然后确保不再存在。您可以通过交叉连接它们来做到这一点,但对于更大的数据集,这将具有糟糕的性能。这样可能会好一点:

-- Set up the source data.
create table MyTable (
        ColumnA int,
        ColumnB nvarchar(max)
    )
insert MyTable
    (ColumnA, ColumnB)
    Values
    -- Value 1 contains exactly the same values as we'll be looking for
    (1, 'abcde'),
    (1, 'xyz'),
    (1, 'abcd'),
    (1, 'abbba'),
    -- Value 2 contains all of them, plus one more different value
    (2, 'abcde'),
    (2, 'xyz'),
    (2, 'abcd'),
    (2, 'abbba'),
    (2, 'xxxxx'),
    -- Value 3 contains one less value
    (3, 'abcde'),
    (3, 'xyz'),
    (3, 'abcd'),
    -- Value 4 contains one different value
    (4, 'abcde'),
    (4, 'xyz'),
    (4, 'abcd'),
    (4, 'xxxxxxxxx')


-- These are the values we are looking for:
create table #searchValues (
            value nvarchar(max)
        )
insert #searchValues
    (value) values
    ('abcde'),
    ('xyz'), 
    ('abcd'), 
    ('abbba')

declare @valueCount int = (select COUNT(*) from #searchValues)


select  t.ColumnA
    from (
        -- This inner query finds all ColumnA values
        -- that link to all of the specified ColumnB values.
        select  tab.ColumnA
            from #searchValues t
            join MyTable tab on
                t.value = tab.ColumnB
            group by tab.ColumnA
            having COUNT(*) = @valueCount
        ) x
    -- And this outer join and group by will filter out those that 
    -- have all the values, plus some more.
    join MyTable t on
        t.ColumnA = x.ColumnA
    group by t.ColumnA
    having COUNT(*) = @valueCount



drop table #searchValues
drop table MyTable

这将只产生值 1,因为它完全匹配。