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