Наилучшая практика объединения двух таблиц с использованием оператора LIKE или более эффективного подхода - PullRequest
0 голосов
/ 01 октября 2019

У меня есть 2 таблицы, которые необходимо обрабатывать один раз в день в хранилище данных.

MessageTable

  • Id целочисленный первичный ключ
  • Message varchar (max)

Пример:

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

PartTable

  • Целевой первичный ключ 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

Поскольку сообщение (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, как показано ниже? Затем в сообщении должны быть найдены все строки слов для детали, чтобы определить, что сообщение принадлежит этой детали.

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

Я могу создать эту таблицу, используя STRING_SPLIT для PartTable, или PartTable можно реорганизовать. Но я не вижу способа присоединиться к этой таблице с помощью MessageTable. Также я ожидаю, что в MessageTable будет много строк.

Кто-нибудь может мне помочь с этим?

Спасибо,

1 Ответ

1 голос
/ 01 октября 2019

Хмммм. ,,Вы можете объединить все части и сообщения и разделить части на слова. Предложение 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 для более быстрого запроса.

...