2013-12-16 89 views
3

我有一个字符串“标识符”的表,我想匹配一个“组”表,找到“最佳匹配”(即:包含较长部分的匹配的字符串)。例如:假设我有两个组:“19”和“19.10”。我要的是:SQL:加入最佳字符串匹配

  • item "19.10.1" is part of the group "19.10"
  • item "19.10.xxxx" is part of the group "19.10"
  • item "19.20" is part of the group "19"

我得到了什么到现在是这样的:

SELECT * FROM Items i 
LEFT JOIN MyGroup g ON g.Prefix = SUBSTRING(i.ItemID,1,LEN(g.Prefix)) 

,所有的字符串相匹配,但我不知道如何过滤“最佳匹配”(即较长的匹配)fr om我的结果。

顺便说一句,我的工作SQL Server 2005的

例如,SQL小提琴上: http://sqlfiddle.com/#!3/9a9d8/1

+0

1)你能改变你的gro的结构吗?起床桌?能够提前分解GroupDesc或添加“分数”列可能会有帮助。 2)您可能需要查看[PARSENAME](http://technet.microsoft.com/en-us/library/ms188006.aspx)函数,这可能有助于抓取对象ID的位,具体取决于它们确切的规格。 –

+0

是的,我可以添加“评分”栏......但我无法理解这对我的情况有何帮助。谢谢你的回复 – Nova

回答

4

试试这一个。

SELECT t.ItemID, g1.prefix, g1.GroupDesc 
FROM Items i1 
LEFT JOIN MyGroup g1 ON g1.Prefix = SUBSTRING(i1.ItemID,1,LEN(g1.Prefix)) 

RIGHT JOIN 

(

    SELECT i2.ItemID, max(len(g2.prefix)) AS ln 
    FROM Items i2 
    LEFT JOIN MyGroup g2 ON g2.Prefix = SUBSTRING(i2.ItemID,1,LEN(g2.Prefix)) 
    GROUP BY i2.ItemID 

) t ON i1.ItemID = t.ItemID AND len(g1.prefix) = t.ln 

您可以测试它在这个测试数据:

CREATE TABLE dbo.MyGroup 
     (GroupDesc VARCHAR(100), 
     Prefix VARCHAR(10)); 
    CREATE TABLE dbo.Items 
     (ItemDesc VARCHAR(100), 
     ItemID VARCHAR(10)); 

    INSERT INTO MyGroup (GroupDesc, Prefix) 
    VALUES ('Group A', '19'); 
    INSERT INTO MyGroup (GroupDesc, Prefix) 
    VALUES ('Group B', '19.10'); 
    INSERT INTO MyGroup (GroupDesc, Prefix) 
    VALUES ('Group C', '19.10.3'); 

    INSERT INTO Items (ItemDesc, ItemID) 
    VALUES ('Item 1', '19.10.4'); 
    INSERT INTO Items (ItemDesc, ItemID) 
    VALUES ('Item 2', '19.10.3'); 
    INSERT INTO Items (ItemDesc, ItemID) 
    VALUES ('Item 3', '19.20'); 
    INSERT INTO Items (ItemDesc, ItemID) 
    VALUES ('Item 4', '44.55'); 
+0

彼得:谢谢。这工作正常。我只是想知道查询是否可以“优化”存储组表中的前缀的长度(如上面评论中所建议的) – Nova

+1

@Nova是的,如果您在组表中存储前缀的长度,查询将变得更简单,因为你将摆脱LEN(g1.Prefix)和LEN(g2.Prefix),并将它们替换为g1.len和g2.len之类的东西。 –

+0

@Nova是的,这就是我的建议 - 有效的是,如果您在组表中存储每个前缀长度的“分数”,生活变得更容易,因为您可以看到哪个匹配具有最高的分数来选择正确的一个。 –

1

我想出了这一点:

with tmp as 
(
    SELECT * FROM Items i 
    LEFT JOIN MyGroup g ON g.Prefix = SUBSTRING(i.ItemID,1,LEN(g.Prefix)) 
) 
SELECT a.* FROM tmp a WHERE LEN(a.prefix) = (SELECT MAX(LEN(b.prefix)) FROM tmp b WHERE a.itemid = b.itemid) 

似乎工作...

SQLFiddle

+0

在上面尝试查询我的测试数据。似乎没有工作。 –

+0

@ peter.petrov也许我不太明白你想要什么。我做了一些改变,现在可以吗? – xpy

+0

不,我不是OP。现在,您的查询更好,但它不会为我的测试数据返回任何'项目4'。但现在好多了,是的。 –