【问题标题】:Select all similar rows that are possible duplicates using LIKE?使用 LIKE 选择所有可能重复的相似行?
【发布时间】:2011-04-08 02:14:29
【问题描述】:

将有关歌曲的信息导入我的 SQLite 数据库后,我想使用 SELECT 语句来查找所有可能使用此条件的重复歌曲:

一行中的歌曲名称与同一表(歌曲)中任何其他行中的歌曲名称相似或相等,并且两行中的艺术家 ID 相同。这应该在不知道歌曲名称的内容的情况下工作。如果我想将已知歌曲名称与数据库中的所有其他歌曲名称进行比较,可以使用“songName LIKE '%known name%'”来完成,但是如果没有这个,我如何找到所有重复项?

示例歌曲表:

id  songName            artistID  duration
--------------------------------------------
0  This is a song       5         3:43
1  Another song         3         3:23
2  01-This is a song    5         3:42
3  song                 4         4:01
4  song                 4         6:33
5  Another record       2         2:45

预期结果:

id  songName            artistID  duration
--------------------------------------------
0   This is a song      5         3:43
2   01-This is a song   5         3:42
3   song                4         4:01
4   song                4         6:33

编辑:

由于提出了创建哈希并比较它们的想法,我正在考虑使用这个伪函数为每个歌曲名称创建一个哈希:

Public Function createHash(ByVal phrase As String) As String
    'convert to lower case
    phrase = LCase(phrase)

    'split the phrase into words
    Dim words() As String = phrase.Replace("_", " ").Split(" ")

    Dim hash As String = ""
    For w = 0 To words.Count - 1
        'remove noise words (a, an, the, etc.)
        words(w) = removeNoiseWords(words(w))
        'convert 1 or 2-digit numbers to corresponding words
        words(w) = number2word(words(w))
    Next

    'rebuild using replaced words and remove spaces
    hash = String.Join("", words)

    'convert upper ascii into alphabetic (ie. ñ = n, Ö = O, etc.)
    hash = removeUnsupChars(hash, True)

    'strip away all remaining non-alphanumeric characters
    hash = REGEX_Replace(hash, "[^A-Za-z0-9]", "")
    Return hash
End Function

计算完哈希后,我会将其与每条记录一起存储,然后使用 count(hash)>1 选择重复项。然后,我将使用 .NET 代码查看返回的记录的艺术家 ID 是否相同。

到目前为止,此解决方案似乎运行良好。这是我用来查找重复歌曲的 SQLite 语句:

SELECT count(*),hash from Songs GROUP BY hash HAVING count(hash) > 1 ORDER BY hash;

这给了我一个多次出现的所有哈希的列表。我将这些结果存储在一个数组中,然后循环遍历该数组并简单地使用此语句来获取详细信息:

    For i = 0 To dupeHashes.Count - 1
        SQLconnect.Open()
        SQLcommand = SQLconnect.CreateCommand
        SQLcommand.CommandText = "SELECT * from Songs WHERE hash = '" & dupeHashes(i) & "';"
        SQLreader = SQLcommand.ExecuteReader()
        While SQLreader.Read()
            'get whatever data needed for each duplicate song
        End While
        SQLcommand.Dispose()
        SQLconnect.Close()
    Next

【问题讨论】:

  • SQLite Full Text Search 用于检索匹配的行。
  • 都在markdown documentation - 添加/编辑问题时可以访问的链接:(
  • 我明白了。回到你的建议。我快速浏览了全文搜索,但你能提供一个例子吗?我不知道如何比较两个未知数(歌曲名称“x”与所有其他歌曲名称)。
  • “简单 FTS 查询”提供了如何使用 FTS 进行搜索的示例
  • 是我一个人,还是我们最近看到很多歌曲相关的sql问题。都有类似的sql表结构,但问的不是同一个问题...奇数

标签: sql sqlite sql-like


【解决方案1】:

我个人会添加一个额外的字段,您可以在其中计算某种标题的“哈希”。一个很好的功能是去除所有非字母字符,包括空格,删除任何文章(如“the”、“a”、“an”),然后计算标题的 soundex code 并在其前加上 artistId字符串。

所以在你的情况下你会得到:

id  songName            artistID  duration  Hash
----------------------------------------------------
0  This is a song       5         3:43      5.T0021
1  Another song         3         3:23      3.A9872
2  01-This is a song    5         3:42      5.T0021
3  song                 4         4:01      4.S0332
4  song                 4         6:33      4.S0332
5  Another record       2         2:45      2.A7622

从现在开始,只获取具有 ...count(Hash)>1 的行应该很容易...

另请注意,我建议使用 Soundex,但您可以创建自己的功能,或调整现有功能,使某些元素比其他元素更相关。

【讨论】:

  • 我曾想过使用 soundex,但结果是很多误报。我确实喜欢预先计算某种类型的哈希并将其与每条记录一起存储的想法。到目前为止,我认为这是最有希望的解决方案。
  • 维基百科页面提到了一些使编码更准确的替代方法。另外,您是否将文章放在标题前面(a,an,the,this...)? Soundex 真正关心的是字符串的第一部分。也许您可以尝试仅保留前 7 个辅音并删除其他所有内容 - 请记住您在此之前添加了歌手 id...
  • 我真的不在乎“听起来像”的匹配。我想要一个比这更精确的匹配,而且有许多歌曲名称以相同的方式开始,可能会返回可能的重复项。查看对我原来问题的修改,看看我的想法。
  • @comp,如果听起来像,那么它很可能是完全匹配的。如果你有两首歌分别叫“Tammie My Love”和“Tammy My Love”,你不希望它们匹配吗?听起来匹配解决了这个问题。我过去曾使用这种方法来根据用户键入的内容来建议已经存在的名称,并且它可以完美地工作。我什至能够计算出匹配的可能性并将其显示为查询结果的一部分。
  • 但是,SOUNDEX 只关心前 2 个音节。如果您想要更少的误报,请从歌曲名称中的每个真实单词创建一个SOUNDEX 散列,并将其存储在附有歌曲 ID 的表中。然后对该表运行查询,找到最可能的匹配项。
【解决方案2】:

可以大致了解一下这个问题,但需要澄清一点: 为什么结果没有 1 另一首歌 3 3:23 记录?因为它可以被视为与那些重复 3歌4 4:01 4 歌 4 6:33 记录?

我只是在tsql中写了一个简单的脚本来解决,效率低,仅供参考。

 drop table #t;
drop table #result;

create table #t 
(
id int ,
songName varchar(100),
artistID int,
duration varchar(20)
)
insert into #t
select '0',  'This is a song'   ,    '5'  ,       '3:43' union all
select '1',  'Another song'     ,    '3'  ,       '3:23' union all
select '2',  '01-This is a song',    '5'  ,       '3:42' union all
select '3',  'song'             ,    '4'  ,       '4:01' union all
select '4',  'song'             ,    '4'  ,       '6:33' union all
select '5',  'Another record'   ,    '2'  ,       '2:45'

select * from #t
select * into #result from #t where 1 = 0

declare @sName varchar(100)
declare @id int
declare @count int

declare c cursor for 
select id, songName from #t

open c
fetch next from c into @id, @sName
while @@FETCH_STATUS = 0
begin
    select @count = COUNT(*) from #result where id = @id
    if @count = 0 
    begin
        select @count = COUNT(*) from #t where songName like '%'+@sName+'%'
        --select @count , @sName
        if @count > 1
        begin
            insert into #result select *  from #t where songName like '%'+@sName+'%' and id not in (select id from #result)
        end
    end
fetch next from c into @id, @sName
end
close c
deallocate c

select * from #result 

【讨论】:

  • 只有在艺术家 ID 相同的情况下才应该匹配。
  • 感谢您的帮助,但什么是“tsql”?这对我来说毫无意义,因为我使用的是 VB.NET 和 SQLite。
猜你喜欢
  • 1970-01-01
  • 2020-06-29
  • 1970-01-01
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多