【问题标题】:Best practice for joinning 2 tables using LIKE operator or better approach使用 LIKE 运算符或更好的方法连接 2 个表的最佳实践
【发布时间】:2019-10-01 14:55:24
【问题描述】:

我有 2 个表必须在数据仓库中每天处理一次。

消息表

  • Id 整数主键
  • 消息 varchar(max)

例子:

Id  | Message
 1  | Hi! This is the first message.
 2  | the last message.

零件表

  • PartId 整数主键
  • 单词 varchar(100)

例子:

PartId | Message
 1     | This
 2     | message, first
 3     | last

表 1 包含要与表 2 进行比较的消息,以便了解每个消息属于哪些部分。

所以上面的例子应该是这样返回的。

Id   | MessageId | PartId
 1   |  1        |  1
 2   |  1        |  2
 3   |  2        |  3

因为 message(id 1) 包含“This”关键字以及“message”和“first”,所以它可以是 0 和 1 的一部分。 当某个部分中的关键字以逗号分隔时,所有关键字都需要在消息中找到,而不考虑顺序。

我为这个过程大致做的存储过程是这样的。

INSERT INTO ResultTable(MessageId, PartId)
    SELECT MessageTable.Id as MessageId, PartTable.Id as PartID
     FROM MessageTable m, PartTable p
    WHERE 
(SELECT COUNT(VALUE) FROM STRING_SPLIT(p.Word, ',') WHERE CHARINDEX(CONCAT(' ', VALUE, ' '), m.Message) > 0) = (SELECT COUNT(VALUE) FROM STRING_SPLIT(p.Word, ','))

即使我没有彻底确认,这条 SQL 语句似乎也可以工作。但这看起来不是一个好习惯。

我是否应该尝试在 PartTable 上使用更多的关系方法,如下所示?然后应该在message中找到一个part的所有单词行来确定message属于这个part。

 Id | PartId | Word
 1  | 1      | This
 2  | 2      | message
 3  | 2      | last

我可以在 PartTable 上使用 STRING_SPLIT 创建此表,或者可以重构 PartTable。但是我看不到用 MessageTable 加入这个表的方法。此外,我预计 MessageTable 中会有很多行。

谁能帮我解决这个问题?

谢谢,

【问题讨论】:

  • 单词必须是单独的单词吗?也就是说,“ThisIsThefirstmessage”是否应该匹配partId 2?
  • @JamieF 不,我希望每个单词都用空格分隔。这就是我使用 CONCAT(' ', VALUE, ' ') 的原因。

标签: sql sql-server join sql-like data-warehouse


【解决方案1】:

嗯嗯。 . .您可以组合所有部分和消息,并将这些部分拆分为单词。 where 子句可用于过滤,因此只包含匹配项。最终聚合和计数返回所有单词匹配的消息/部分对:

select m.id, pt.partid
from message m cross join
     parttable pt cross apply
     string_split(pt.words, ',') s
where m.message like '%' + s.value + '%'
group by m.id, pt.partid
having count(*) = (select count(*)
                   from parttable pt2 cross apply
                        string_split(pt.words, ',') s
                   where pt2.partid = pt.partid
                  );

这效率不高,而且鉴于您的数据结构,很难在 SQL Server 中进行优化。

parttable 的更好结构将是对查询的改进:

select m.id, ptn.partid
from message m join
     (select ptn.*, count(*) over (partition by partid) as cnt
      from parttablenormalized ptn 
     ) ptn
     on m.message like '%' + ptn.word + '%'
group by m.id, pnt.partid, cnt
having count(*) = cnt;

但是性能可能不会有太大变化。您还需要对 message 进行非规范化以加快查询速度。

【讨论】:

  • 你能给我提供一些去噪消息的例子吗? MessageTable 仅包含 id 和消息正文。我看不到如何非规范化消息。
猜你喜欢
  • 2015-07-02
  • 2020-09-18
  • 1970-01-01
  • 2012-09-28
  • 2011-03-19
  • 1970-01-01
  • 2021-02-15
  • 2015-08-06
相关资源
最近更新 更多