T-SQL,在执行多重连接和分组时连接字符串

T-SQL,在执行多重连接和分组时连接字符串,sql,sql-server,string,tsql,inner-join,Sql,Sql Server,String,Tsql,Inner Join,我不想在执行多重连接时将组中的所有字符串连接起来。下面是我的情景 表-日志 id | appname | level --------------------- 1 | app1 | debug 2 | app3 | warn 3 | app1 | debug 4 | app2 | info id | text ---------- 1 | tag_wink 2 | tag_steve 3 | ignore 4 | jimmy 表-日志标签 id |

我不想在执行多重连接时将组中的所有字符串连接起来。下面是我的情景

表-日志

id | appname | level
---------------------
1  | app1    | debug
2  | app3    | warn
3  | app1    | debug
4  | app2    | info
id | text
----------
1  | tag_wink
2  | tag_steve
3  | ignore
4  | jimmy
表-日志标签

id | appname | level
---------------------
1  | app1    | debug
2  | app3    | warn
3  | app1    | debug
4  | app2    | info
id | text
----------
1  | tag_wink
2  | tag_steve
3  | ignore
4  | jimmy
表-日志标签地图

tag_id | log_id
---------------
1      | 1
1      | 2
2      | 4
2      | 1
3      | 1
我的目标是;对于每个日志,连接所有以逗号分隔的标记

这是我想要的输出

id | appname | level | text
----------------------------
1  | app1    | debug | tag_wink, tag_steve, ignore
2  | app3    | warn  | tag_wink
3  | app1    | debug | 
4  | app2    | info  | tag_steve
我尝试了很多东西,但似乎都没有达到预期的效果

这将为每个日志提供一个标记文本

SELECT 
    log_table.id,
    log_table.appname,
    log_table.level,
    log_tag_table.text,
FROM log_table
INNER JOIN [log_tag_map] log_tag_map_table  
    ON log_tag_map_table.log_id = log_table.id
INNER JOIN [log_tag] log_tag_table 
    ON log_tag_map_table.tag_id = log_tag_table.id
ORDER BY log_table.id
在研究了T-SQL中的串接之后,我使用了著名的FOR XML PATH解决方案,但似乎没有得到我想要的结果。我不断收到错误消息说“log\u tag\u map\u table.tag\u id”无效,因为它不在聚合函数中

SELECT 
    log_table.id,
    MAX(log_table.appname),
    MAX(log_table.level),
    STUFF((
        SELECT ', ' + [log_tag].text 
        FROM [log_tag] 
        WHERE
            log_tag_map_table.tag_id = log_tag.id AND 
            log_tag_map_table.log_id = log_table.id
        FOR XML PATH (''))
        , 1
        , 2
        , '')
FROM log_table
INNER JOIN [log_tag_map] log_tag_map_table  
    ON log_tag_map_table.log_id = log_table.id
INNER JOIN [log_tag] log_tag_table 
    ON log_tag_map_table.tag_id = log_tag_table.id
GROUP BY log_table.id
ORDER BY log_table.id

您可以通过在
Group by
中添加重命名列来修复此问题。查询中的
分组依据
仅用于删除重复项

我更喜欢
APPLY
操作符而不是
相关子查询
。它看起来很简单,删除前导或尾随的
逗号
非常容易

SELECT DISTINCT log_table.id,
                log_table.appname,
                log_table.level,
                LEFT(concat_text, Len(concat_text) - 1) as Concat_text
FROM   log_table
       OUTER apply (SELECT [log_tag].text + ','
                    FROM   [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
                    FOR XML PATH ('')) oa (concat_text) 
ORDER BY log_table.id
演示:

SELECT DISTINCT log_table.id,
                log_table.appname,
                log_table.level,
                LEFT(concat_text, Len(concat_text) - 1) as Concat_Text
FROM   log_table
       OUTER apply (SELECT [log_tag].text + ','
                    FROM   [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
                    FOR XML PATH ('')) oa (concat_text) 
Order by log_table.id
╔════╦═════════╦═══════╦═══════════════════════════╗
║ id ║ appname ║ level ║        Concat_Text        ║
╠════╬═════════╬═══════╬═══════════════════════════╣
║  1 ║ app1    ║ debug ║ tag_wink,tag_steve,ignore ║
║  2 ║ app3    ║ warn  ║ tag_wink                  ║
║  3 ║ app1    ║ debug ║ NULL                      ║
║  4 ║ app2    ║ info  ║ tag_steve                 ║
╚════╩═════════╩═══════╩═══════════════════════════╝
架构设置

CREATE TABLE log_table
  (
     [id]      INT,
     [appname] VARCHAR(4),
     [level]   VARCHAR(5)
  );

CREATE TABLE log_tag
  (
     [id]   INT,
     [text] VARCHAR(9)
  );

CREATE TABLE log_tag_map
  (
     [tag_id] INT,
     [log_id] INT
  );
INSERT INTO log_table
            ([id],[appname],[level])
VALUES      (1,'app1','debug'),
            (2,'app3','warn'),
            (3,'app1','debug'),
            (4,'app2','info');


INSERT INTO log_tag
            ([id],[text])
VALUES      (1,'tag_wink'),
            (2,'tag_steve'),
            (3,'ignore'),
            (4,'jimmy');



INSERT INTO log_tag_map
            ([tag_id],[log_id])
VALUES      (1,1),
            (1,2),
            (2,4),
            (2,1),
            (3,1);
样本数据

CREATE TABLE log_table
  (
     [id]      INT,
     [appname] VARCHAR(4),
     [level]   VARCHAR(5)
  );

CREATE TABLE log_tag
  (
     [id]   INT,
     [text] VARCHAR(9)
  );

CREATE TABLE log_tag_map
  (
     [tag_id] INT,
     [log_id] INT
  );
INSERT INTO log_table
            ([id],[appname],[level])
VALUES      (1,'app1','debug'),
            (2,'app3','warn'),
            (3,'app1','debug'),
            (4,'app2','info');


INSERT INTO log_tag
            ([id],[text])
VALUES      (1,'tag_wink'),
            (2,'tag_steve'),
            (3,'ignore'),
            (4,'jimmy');



INSERT INTO log_tag_map
            ([tag_id],[log_id])
VALUES      (1,1),
            (1,2),
            (2,4),
            (2,1),
            (3,1);
查询:

SELECT DISTINCT log_table.id,
                log_table.appname,
                log_table.level,
                LEFT(concat_text, Len(concat_text) - 1) as Concat_Text
FROM   log_table
       OUTER apply (SELECT [log_tag].text + ','
                    FROM   [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
                    FOR XML PATH ('')) oa (concat_text) 
Order by log_table.id
╔════╦═════════╦═══════╦═══════════════════════════╗
║ id ║ appname ║ level ║        Concat_Text        ║
╠════╬═════════╬═══════╬═══════════════════════════╣
║  1 ║ app1    ║ debug ║ tag_wink,tag_steve,ignore ║
║  2 ║ app3    ║ warn  ║ tag_wink                  ║
║  3 ║ app1    ║ debug ║ NULL                      ║
║  4 ║ app2    ║ info  ║ tag_steve                 ║
╚════╩═════════╩═══════╩═══════════════════════════╝
重用lt:

SELECT DISTINCT log_table.id,
                log_table.appname,
                log_table.level,
                LEFT(concat_text, Len(concat_text) - 1) as Concat_Text
FROM   log_table
       OUTER apply (SELECT [log_tag].text + ','
                    FROM   [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
                    FOR XML PATH ('')) oa (concat_text) 
Order by log_table.id
╔════╦═════════╦═══════╦═══════════════════════════╗
║ id ║ appname ║ level ║        Concat_Text        ║
╠════╬═════════╬═══════╬═══════════════════════════╣
║  1 ║ app1    ║ debug ║ tag_wink,tag_steve,ignore ║
║  2 ║ app3    ║ warn  ║ tag_wink                  ║
║  3 ║ app1    ║ debug ║ NULL                      ║
║  4 ║ app2    ║ info  ║ tag_steve                 ║
╚════╩═════════╩═══════╩═══════════════════════════╝

您可以通过在
Group by
中添加重命名列来修复此问题。查询中的
分组依据
仅用于删除重复项

我更喜欢
APPLY
操作符而不是
相关子查询
。它看起来很简单,删除前导或尾随的
逗号
非常容易

SELECT DISTINCT log_table.id,
                log_table.appname,
                log_table.level,
                LEFT(concat_text, Len(concat_text) - 1) as Concat_text
FROM   log_table
       OUTER apply (SELECT [log_tag].text + ','
                    FROM   [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
                    FOR XML PATH ('')) oa (concat_text) 
ORDER BY log_table.id
演示:

SELECT DISTINCT log_table.id,
                log_table.appname,
                log_table.level,
                LEFT(concat_text, Len(concat_text) - 1) as Concat_Text
FROM   log_table
       OUTER apply (SELECT [log_tag].text + ','
                    FROM   [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
                    FOR XML PATH ('')) oa (concat_text) 
Order by log_table.id
╔════╦═════════╦═══════╦═══════════════════════════╗
║ id ║ appname ║ level ║        Concat_Text        ║
╠════╬═════════╬═══════╬═══════════════════════════╣
║  1 ║ app1    ║ debug ║ tag_wink,tag_steve,ignore ║
║  2 ║ app3    ║ warn  ║ tag_wink                  ║
║  3 ║ app1    ║ debug ║ NULL                      ║
║  4 ║ app2    ║ info  ║ tag_steve                 ║
╚════╩═════════╩═══════╩═══════════════════════════╝
架构设置

CREATE TABLE log_table
  (
     [id]      INT,
     [appname] VARCHAR(4),
     [level]   VARCHAR(5)
  );

CREATE TABLE log_tag
  (
     [id]   INT,
     [text] VARCHAR(9)
  );

CREATE TABLE log_tag_map
  (
     [tag_id] INT,
     [log_id] INT
  );
INSERT INTO log_table
            ([id],[appname],[level])
VALUES      (1,'app1','debug'),
            (2,'app3','warn'),
            (3,'app1','debug'),
            (4,'app2','info');


INSERT INTO log_tag
            ([id],[text])
VALUES      (1,'tag_wink'),
            (2,'tag_steve'),
            (3,'ignore'),
            (4,'jimmy');



INSERT INTO log_tag_map
            ([tag_id],[log_id])
VALUES      (1,1),
            (1,2),
            (2,4),
            (2,1),
            (3,1);
样本数据

CREATE TABLE log_table
  (
     [id]      INT,
     [appname] VARCHAR(4),
     [level]   VARCHAR(5)
  );

CREATE TABLE log_tag
  (
     [id]   INT,
     [text] VARCHAR(9)
  );

CREATE TABLE log_tag_map
  (
     [tag_id] INT,
     [log_id] INT
  );
INSERT INTO log_table
            ([id],[appname],[level])
VALUES      (1,'app1','debug'),
            (2,'app3','warn'),
            (3,'app1','debug'),
            (4,'app2','info');


INSERT INTO log_tag
            ([id],[text])
VALUES      (1,'tag_wink'),
            (2,'tag_steve'),
            (3,'ignore'),
            (4,'jimmy');



INSERT INTO log_tag_map
            ([tag_id],[log_id])
VALUES      (1,1),
            (1,2),
            (2,4),
            (2,1),
            (3,1);
查询:

SELECT DISTINCT log_table.id,
                log_table.appname,
                log_table.level,
                LEFT(concat_text, Len(concat_text) - 1) as Concat_Text
FROM   log_table
       OUTER apply (SELECT [log_tag].text + ','
                    FROM   [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
                    FOR XML PATH ('')) oa (concat_text) 
Order by log_table.id
╔════╦═════════╦═══════╦═══════════════════════════╗
║ id ║ appname ║ level ║        Concat_Text        ║
╠════╬═════════╬═══════╬═══════════════════════════╣
║  1 ║ app1    ║ debug ║ tag_wink,tag_steve,ignore ║
║  2 ║ app3    ║ warn  ║ tag_wink                  ║
║  3 ║ app1    ║ debug ║ NULL                      ║
║  4 ║ app2    ║ info  ║ tag_steve                 ║
╚════╩═════════╩═══════╩═══════════════════════════╝
重用lt:

SELECT DISTINCT log_table.id,
                log_table.appname,
                log_table.level,
                LEFT(concat_text, Len(concat_text) - 1) as Concat_Text
FROM   log_table
       OUTER apply (SELECT [log_tag].text + ','
                    FROM   [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
                    FOR XML PATH ('')) oa (concat_text) 
Order by log_table.id
╔════╦═════════╦═══════╦═══════════════════════════╗
║ id ║ appname ║ level ║        Concat_Text        ║
╠════╬═════════╬═══════╬═══════════════════════════╣
║  1 ║ app1    ║ debug ║ tag_wink,tag_steve,ignore ║
║  2 ║ app3    ║ warn  ║ tag_wink                  ║
║  3 ║ app1    ║ debug ║ NULL                      ║
║  4 ║ app2    ║ info  ║ tag_steve                 ║
╚════╩═════════╩═══════╩═══════════════════════════╝

下面是使用
素材的方法

SELECT  log_table.id,
        log_table.appname,
        log_table.level,
       STUFF((SELECT ', ' + [log_tag].text [text()]
         FROM [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
         FOR XML PATH('')),1,2,' ') text
FROM log_table 
输出:

SELECT DISTINCT log_table.id,
                log_table.appname,
                log_table.level,
                LEFT(concat_text, Len(concat_text) - 1) as Concat_Text
FROM   log_table
       OUTER apply (SELECT [log_tag].text + ','
                    FROM   [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
                    FOR XML PATH ('')) oa (concat_text) 
Order by log_table.id
╔════╦═════════╦═══════╦═══════════════════════════╗
║ id ║ appname ║ level ║        Concat_Text        ║
╠════╬═════════╬═══════╬═══════════════════════════╣
║  1 ║ app1    ║ debug ║ tag_wink,tag_steve,ignore ║
║  2 ║ app3    ║ warn  ║ tag_wink                  ║
║  3 ║ app1    ║ debug ║ NULL                      ║
║  4 ║ app2    ║ info  ║ tag_steve                 ║
╚════╩═════════╩═══════╩═══════════════════════════╝

您还可以使用
交叉应用
获得OP

SELECT  Id ,appname,level,[text]
FROM    (
        SELECT   log_table.id,
        log_table.appname,
        log_table.level
        FROM    log_table
        ) a
CROSS APPLY
        (
        SELECT  CASE ROW_NUMBER() OVER(ORDER BY [log_tag].text) WHEN 1 THEN '' ELSE ', ' END +[log_tag].text [text()]
        FROM [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = a.id
        ORDER BY
                [log_tag].text
        FOR XML PATH ('')
        ) b([text])
输出:

SELECT DISTINCT log_table.id,
                log_table.appname,
                log_table.level,
                LEFT(concat_text, Len(concat_text) - 1) as Concat_Text
FROM   log_table
       OUTER apply (SELECT [log_tag].text + ','
                    FROM   [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
                    FOR XML PATH ('')) oa (concat_text) 
Order by log_table.id
╔════╦═════════╦═══════╦═══════════════════════════╗
║ id ║ appname ║ level ║        Concat_Text        ║
╠════╬═════════╬═══════╬═══════════════════════════╣
║  1 ║ app1    ║ debug ║ tag_wink,tag_steve,ignore ║
║  2 ║ app3    ║ warn  ║ tag_wink                  ║
║  3 ║ app1    ║ debug ║ NULL                      ║
║  4 ║ app2    ║ info  ║ tag_steve                 ║
╚════╩═════════╩═══════╩═══════════════════════════╝

以下是使用
素材的方法

SELECT  log_table.id,
        log_table.appname,
        log_table.level,
       STUFF((SELECT ', ' + [log_tag].text [text()]
         FROM [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
         FOR XML PATH('')),1,2,' ') text
FROM log_table 
输出:

SELECT DISTINCT log_table.id,
                log_table.appname,
                log_table.level,
                LEFT(concat_text, Len(concat_text) - 1) as Concat_Text
FROM   log_table
       OUTER apply (SELECT [log_tag].text + ','
                    FROM   [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
                    FOR XML PATH ('')) oa (concat_text) 
Order by log_table.id
╔════╦═════════╦═══════╦═══════════════════════════╗
║ id ║ appname ║ level ║        Concat_Text        ║
╠════╬═════════╬═══════╬═══════════════════════════╣
║  1 ║ app1    ║ debug ║ tag_wink,tag_steve,ignore ║
║  2 ║ app3    ║ warn  ║ tag_wink                  ║
║  3 ║ app1    ║ debug ║ NULL                      ║
║  4 ║ app2    ║ info  ║ tag_steve                 ║
╚════╩═════════╩═══════╩═══════════════════════════╝

您还可以使用
交叉应用
获得OP

SELECT  Id ,appname,level,[text]
FROM    (
        SELECT   log_table.id,
        log_table.appname,
        log_table.level
        FROM    log_table
        ) a
CROSS APPLY
        (
        SELECT  CASE ROW_NUMBER() OVER(ORDER BY [log_tag].text) WHEN 1 THEN '' ELSE ', ' END +[log_tag].text [text()]
        FROM [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = a.id
        ORDER BY
                [log_tag].text
        FOR XML PATH ('')
        ) b([text])
输出:

SELECT DISTINCT log_table.id,
                log_table.appname,
                log_table.level,
                LEFT(concat_text, Len(concat_text) - 1) as Concat_Text
FROM   log_table
       OUTER apply (SELECT [log_tag].text + ','
                    FROM   [log_tag_map] log_tag_map_table
                           JOIN log_tag
                             ON log_tag_map_table.tag_id = log_tag.id
                    WHERE  log_tag_map_table.log_id = log_table.id
                    FOR XML PATH ('')) oa (concat_text) 
Order by log_table.id
╔════╦═════════╦═══════╦═══════════════════════════╗
║ id ║ appname ║ level ║        Concat_Text        ║
╠════╬═════════╬═══════╬═══════════════════════════╣
║  1 ║ app1    ║ debug ║ tag_wink,tag_steve,ignore ║
║  2 ║ app3    ║ warn  ║ tag_wink                  ║
║  3 ║ app1    ║ debug ║ NULL                      ║
║  4 ║ app2    ║ info  ║ tag_steve                 ║
╚════╩═════════╩═══════╩═══════════════════════════╝

尝试了此操作,但仍然没有提供所需的输出(所有文本均以“,”)连接。谢谢,更新的查询似乎完成了任务。我得想想Join会解决我所有的问题。尝试过这个,但仍然没有提供所需的输出(所有文本都以“,”)连接。谢谢,更新的查询似乎完成了任务。我得想一想加入会解决我所有的问题。