Короче говоря, нужна подпись для каждого абзаца, а затем сравнить подписи. Вы не указали природу самого выхода. . Здесь, я "м возвращающая строку разделенных запятыми значений ParagraphId для каждого идентичного пункта подписи
With ParagraphSigs As
(
Select P.ParagraphId
, Hashbytes('SHA1'
, (
Select '|' + S1.Text
'|' + Cast(S1.Offset As varchar(10))
'|' + Cast(S1.Score As varchar(10))
From Sentence As S1
Where S1.ParagraphId = P.ParagraphId
Order By S1.SentenceId
For Xml Path('')
)) As Signature
From Paragraph As P
)
Select Stuff(
(
Select ', ' + Cast(PS1.ParagraphId As varchar(10))
From ParagraphSigs As PS1
Where PS1.Signature = PS.Signature
For Xml Path('')
), 1, 2, '') As Paragraph
From ParagraphSigs As PS
Group By PS.Signature
Учитывая ваше добавление о желаемом выходе, вы можете изменить запрос следующим образом:
With ParagraphSigs As
(
Select P.ParagraphId
, Hashbytes('SHA1'
, (
Select '|' + S1.Text
'|' + Cast(S1.Offset As varchar(10))
'|' + Cast(S1.Score As varchar(10))
From Sentence As S1
Where S1.ParagraphId = P.ParagraphId
Order By S1.SentenceId
For Xml Path('')
)) As Signature
From Paragraph As P
)
Select P1.ParagraphId, P2.ParagraphId As EquivParagraphId
From ParagraphSigs As P1
Left Join ParagraphSigs As P2
On P2.Signature = P1.Signature
And P2.ParagraphId <> P1.ParagraphId
Очевидно, возможно, что три или четыре абзаца разделяют одну и ту же подпись, поэтому следует предупредить, что приведенные выше результаты дадут вам декартово произведение соответствующих абзацев (например, (P1, P2), (P1, P3), (P2, P1), (P2, P3), (P3, P1), (P3, P2)).
В комментариях вы ответили abo эффективный поиск последнего предложения. Поскольку у вас есть два других параметра, можно уменьшить количество подписей, генерируемых делая путем сравнения на двух ИНТ столбцов первой:
With ParagraphsNeedingSigs As
(
Select P1.ParagraphId
From Paragraph As P1
Where Exists (
Select 1
From Paragraph As P2
Where P2.ParagraphId <> P1.ParagraphId
And P2.Offset = P1.Offet
And P2.Score = P1.Score
)
)
, ParagraphSigs As
(
Select P.ParagraphId
, Hashbytes('SHA1'
, (
Select '|' + S1.Text
'|' + Cast(S1.Offset As varchar(10))
'|' + Cast(S1.Score As varchar(10))
From Sentence As S1
Where S1.ParagraphId = P.ParagraphId
Order By S1.SentenceId
For Xml Path('')
)) As Signature
From ParagraphsNeedingSigs As P
)
Select P.ParagraphId, P2.ParagraphId As EquivParagraphId
From Paragraph As P
Left Join ParagraphSigs As P1
On P1.ParagraphId = P.ParagraphId
Left Join ParagraphSigs As P2
On P2.Signature = P1.Signature
And P2.ParagraphId <> P1.ParagraphId
Благодарим вас за это. Раньше я не видел хеш-функцию, так что это был глазник. Даже если ложное совпадение статистически незначительно, есть ли способ использовать ключ как подсказку для равных абзацев, но все же использовать сравнение предложений, чтобы быть полностью уверенным? Также см. Мое обновление о желаемом выходе. – mdma
@mdma - Я обновил свой пост. Короче говоря, вы можете отфильтровать абзацы, которые не имеют потенциального соответствия, на основе двух столбцов int, а затем вычисляют хэши для тех, у кого есть потенциальное совпадение. – Thomas
Мой последний запрос был очень похож на этот. Я попытался также комбинировать это с INTERSECT, чтобы отсеять хеш-коллизии и убедиться, что наборы предложений были действительно равны, но накладные расходы заняли это от нескольких секунд до нескольких минут (я никогда не позволяю ему завершать.) Вместо этого я изменил хэш на ссылайтесь на фактические данные, чтобы они были уникальными. – mdma