Sql Join Tables Partial Join连接结果?

时间:2012-08-20 15:03:42

标签: sql sql-server-2008 join concatenation partial

我有两张桌子。一个有2列 - ID,标签。标签列是标记值的逗号分隔列表。

我在第二张表中,还有两列。一个是标签列表,每个标签都在自己的行中,第二列是该标签的标签。

我需要做的是为每个ID创建一个输出查询,每个ID都有一个以分号分隔的标签标签列表,每个ID在其列表中都有相应的标签值。

以下是两个表的简短示例:

Table1 - 
ID---Tags
1---tag1,tag2,tag3,tag6
2---tag2,tag4,tag5
3---tag3,tag8,tag9,tag10
4---tag1,tag2,tag6
5---tag1,tag4,tag5

Table2 - 
tagname---taglabel
tag1--- Nice Name Tag1
tag2--- Nice Name Tag2
tag3--- Nice Name Tag3
tag4--- Nice Name Tag4
tag5--- Nice Name Tag5
tag6--- Nice Name Tag6
tag7--- Nice Name Tag7
tag8--- Nice Name Tag8
tag9--- Nice Name Tag9
tag10--- Nice Name Tag10

期望的结果集 -

ID---TagsNames
1---Nice Name Tag1,Nice Name Tag2,Nice Name Tag3,Nice Name Tag6
2---Nice Name Tag2,Nice Name Tag4,Nice Name Tag5
3---Nice Name Tag3,Nice Name Tag8,Nice Name Tag9,Nice Name Tag10
4---Nice Name Tag1,Nice Name Tag2,Nice Name Tag6
5---Nice Name Tag1,Nice Name Tag4,Nice Name Tag5

我尝试为初始连接设置查询,认为我可以获取结果集并连接行,但我似乎无法使部分连接起作用。这是查询:

 SELECT gt.id as g
      ,gt.tags as tg
      ,tt.HitTagName as ht
      ,tt.termlabel as tl 
FROM tblidtags gt (nolock)
JOIN tbltaglabels tt (Nolock) ON gt.tg like '%' + tt.ht + '%'

非常感谢任何建议!

2 个答案:

答案 0 :(得分:1)

首先,如果你可以,normalize表而不是多值列。这是一个糟糕的数据库设计,很难查询,正如您将看到的那样。

现在,如果您真的无法修改数据库架构,请执行以下操作:

  1. 将每个多值列转换为行,即tag1,tag2,tag3为三行;
  2. 对于每一行,从Table2;
  3. 获取其描述
  4. 最后,连接所有描述,按ID分组。
  5. 以下是生成的查询和正常工作 sqlfiddle

    WITH tmp (id, tag, tags) AS (
    SELECT id, LEFT(tags, CHARINDEX(',',tags+',')-1),
        STUFF(tags, 1, CHARINDEX(',',tags+','), '')
    FROM tbl1
    UNION ALL
    SELECT id, LEFT(tags, CHARINDEX(',',tags+',')-1),
        STUFF(tags, 1, CHARINDEX(',',tags+','), '')
    FROM tmp
    WHERE tag > ''
    )
    SELECT id, 
     STUFF((SELECT ',' + tbl2.descr FROM tmp INNER JOIN tbl2 ON (tmp.tag = tbl2.tag) 
            WHERE id = a.id
            FOR XML PATH ('')), 1, 1, '') tag_names
    FROM tmp a
    WHERE tag != ''
    GROUP BY id
    ORDER BY id;
    

    要规范化架构,您需要创建一个中间表,例如id_tag(id, tag),其中(id, tag)将构成主键。然后,您可以使用上述查询的第一部分(tmp表)来填充此表。在此之后,您可以删除Table1

答案 1 :(得分:1)

;WITH cte AS (
    SELECT a.ID, b.taglabel FROM
        (SELECT c.ID, Split.a.value('.', 'VARCHAR(100)') AS Tags FROM 
            (SELECT ID, CAST('<M>' + REPLACE(Tags,  ',' , '</M><M>') + '</M>' AS XML) AS Tag 
                FROM dbo.Table1) c
        CROSS APPLY Tag.nodes('/M') Split(a)) a
    LEFT JOIN dbo.Table2 b ON b.tagname = a.Tags)

SELECT ID, STUFF(
    (SELECT DISTINCT ',' + NULLIF(taglabel,'') FROM cte t2
        WHERE t1.id = t2.id FOR XML PATH(''), TYPE).value('.','VARCHAR(MAX)'),1,2,'') AS tags
FROM cte t1 GROUP BY ID ORDER BY ID

模式

CREATE TABLE dbo.Table1 (
    ID tinyint PRIMARY KEY,
    Tags varchar(25))

CREATE TABLE dbo.Table2(
    tagname varchar(5) PRIMARY KEY,
    taglabel varchar(15))

INSERT INTO dbo.Table1 VALUES
(1, 'tag1,tag2,tag3,tag6'),
(2, 'tag2,tag4,tag5'),
(3, 'tag3,tag8,tag9,tag10'),
(4, 'tag1,tag2,tag6'),
(5, 'tag1,tag4,tag5')

INSERT INTO dbo.Table2 VALUES
('tag1', 'Nice Name Tag1'),
('tag2', 'Nice Name Tag2'),
('tag3', 'Nice Name Tag3'),
('tag4', 'Nice Name Tag4'),
('tag5', 'Nice Name Tag5'),
('tag6', 'Nice Name Tag6'),
('tag7', 'Nice Name Tag7'),
('tag8', 'Nice Name Tag8'),
('tag9', 'Nice Name Tag9'),
('tag10', 'Nice Name Tag10')

结果

ID   tags
---- ------------------------------------------------------------------
1    Nice Name Tag1,Nice Name Tag2,Nice Name Tag3,Nice Name Tag6
2    Nice Name Tag2,Nice Name Tag4,Nice Name Tag5
3    Nice Name Tag10,Nice Name Tag3,Nice Name Tag8,Nice Name Tag9
4    Nice Name Tag1,Nice Name Tag2,Nice Name Tag6
5    Nice Name Tag1,Nice Name Tag4,Nice Name Tag5

编辑1

要标准化,请创建另一个表:

CREATE TABLE tags (
    id mediumint,
    tag varchar(5),
    PRIMARY KEY (id, tag))

INSERT INTO tags (id, tag) VALUES
SELECT c.ID, Split.a.value('.', 'VARCHAR(100)') AS Tags FROM 
    (SELECT ID, CAST('<M>' + REPLACE(Tags,  ',' , '</M><M>') + '</M>' AS XML) AS Tag 
        FROM dbo.Table1) c
CROSS APPLY Tag.nodes('/M') Split(a)

然后,您可以JOIN tags tag上的{{1}}。

编辑2

查看this小提琴,了解规范化架构的外观。