【问题标题】:where not in / where not like subquerywhere not in / where not like 子查询
【发布时间】:2014-03-03 14:14:03
【问题描述】:

有人可以帮我做一个 MS-SQL 查询吗?

我有以下:

select Name from Keyword.dbo.NGrams
where Name not in (select Name from Keyword.dbo.Brands)

我真正想要的是这样的东西,但我无法正确使用语法

select Name from Keyword.dbo.NGrams
where Name not like (select Name from Keyword.dbo.Brands)

“不在”非常适合完全匹配的 Ngram 和品牌。但我的 NGram 有多个单词,其中一些包含品牌。

非常感谢

编辑:也许我可以重新澄清我在寻找我的这个伪 sql:

从 Keyword.dbo.NGrams 中选择名称 其中描述不包含(从 Keyword.dbo.Brands 中选择单词)

品牌是单个单词的列表。 NGrams 中的描述将是一个 2 或 3 个单词的短语。我想选择所有不包含任何品牌的 NGrams

【问题讨论】:

  • 您能否展示一下您的数据的外观,这很容易弄清楚。
  • Brand.Name 类似于“Nike”。 NGram.Name 类似于“Green Nike Shoes”。
  • 尝试在一个临时表中获取所有匹配的名称,并将您的相同查询与临时表进行比较。它应该可以正常工作。
  • 你想过滤掉像“消化不良dysPEPSIa”这样的NGram吗?
  • 不需要整个单词

标签: sql-server tsql sql-server-2012


【解决方案1】:
SELECT
  n.Name
FROM Keyword.dbo.NGrams n
LEFT JOIN Keyword.dbo.Brands b
  ON n.Name LIKE '%'+b.Name+'%'
WHERE b.Name IS NULL

SQL Fiddle Demo

如果您想避免Scunthorpe Problem 并且只匹配整个单词,请将连接条件更改为:

  ON ' '+n.Name+' ' LIKE '% '+b.Name+' %'

【讨论】:

  • 与此相关的小问题是连接可能会与 Keyword.dbo.NGrams n 中的名称重复,其中 LIKE 满足多个名称。
  • @KRichard 在 SQL Fiddle 示例中,有匹配多个品牌的 NGram。输出没有重复。您是否有产生重复的样本数据?
  • @Anon 是的,你是对的。我专注于连接,我认为它可以返回 dups,但是任何匹配的 dups 都会被 WHERE b.Name IS NULL 消除
  • @Anon 不应该按照 OP 的要求不应该吗?
  • @IndoKnight 不,不应该。稍微玩一下 SQL Fiddle 示例,看看为什么。
【解决方案2】:

使用where not exists 表示类似:

select Name 
from Keyword.dbo.NGrams ng
where not exists (
    select *
    from Keyword.dbo.Brands b
    where ng.Name like '%' + b.name + '%'
)

【讨论】:

  • 此查询还将我返回的结果从 280 000 减少到 544,这也是不正确的。但它比第一个解决方案运行得快得多。 37 分钟与 4 小时
  • @Trevor 如果您的问题的两种不同解决方案产生完全相同数量的结果,而您都拒绝了两者,那么您可能问错了问题。
【解决方案3】:

我使用 ENABLE2K 标准英语单词列表进行了测试。我生成了 1000 万个随机 ngram 和 50000 个随机品牌。在我的工作站上运行该查询大约需要 1 分钟。

CREATE TABLE #enable2k (word varchar(max) NOT NULL)
BULK INSERT #enable2k FROM 'C:\enable2k.txt'

CREATE TABLE #ngrams (ngram_id int NOT NULL, word_num int NOT NULL, word varchar(max) NOT NULL, PRIMARY KEY(ngram_id, word_num));
INSERT #ngrams SELECT TOP 10000000 ROW_NUMBER() OVER(ORDER BY NEWID()), 1, word FROM #enable2k,(SELECT TOP 58 0 FROM master..spt_values) t(i)
INSERT #ngrams SELECT TOP 10000000 ROW_NUMBER() OVER(ORDER BY NEWID()), 2, word FROM #enable2k,(SELECT TOP 58 0 FROM master..spt_values) t(i)
INSERT #ngrams SELECT TOP 10000000 ROW_NUMBER() OVER(ORDER BY NEWID()), 3, word FROM #enable2k,(SELECT TOP 58 0 FROM master..spt_values) t(i)

CREATE TABLE #brands (brand varchar(32) NOT NULL PRIMARY KEY)
INSERT #brands SELECT TOP 50000 word FROM #enable2k WHERE LEN(word) <= 32 ORDER BY NEWID()

SELECT *
FROM #ngrams n
PIVOT (MIN(word) FOR word_num IN ([1],[2],[3])) n1
WHERE NOT EXISTS (
  SELECT 1
  FROM #ngrams n2
  INNER JOIN #brands b
    ON (n2.word = b.brand)
  WHERE n1.ngram_id = n2.ngram_id
)

【讨论】:

  • 嗯,这看起来很有趣,因为我已经将 NGrams 标准化。让我试一试!
  • 运气不好。无论有无 where 不存在,我都会得到相同数量的结果。我对 sql 的理解不够深入,无法理解为什么
  • 发布您的实际架构和索引。
猜你喜欢
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 2012-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-28
  • 2021-03-17
相关资源
最近更新 更多