【问题标题】:Make string_agg() return unique values only [duplicate]使 string_agg() 仅返回唯一值[重复]
【发布时间】:2021-12-23 09:25:12
【问题描述】:

我在 SQL Server 2017 中工作,我有以下两个表:

create table Computer (
  Id int Identity(1, 1) not null,
  Name varchar(100) not null,
  constraint pk_computer primary key (Id)
);

create table HardDisk (
  Id int Identity(1, 1) not null,
  Interface varchar(100) not null,
  ComputerId int not null,
  constraint pk_harddisk primary key (Id),
  constraint fk_computer_harddisk foreign key (ComputerId) references Computer(Id)
);

我有如下数据:

查询

我当前的查询如下:

-- select query
select c.Id as computer_id,
       string_agg(cast(hd.Interface as nvarchar(max)), ' ') as hard_disk_interfaces
from Computer c
left join HardDisk hd on c.Id = hd.ComputerId
group by c.Id;

这让我得到以下信息:

 computer_id | hard_disk_interfaces
-------------+----------------------
 1           | SATA SAS
 2           | SATA SAS SAS SAS SATA

但是,我只想要不同的值,我想最终得到:

 computer_id | hard_disk_interfaces
-------------+----------------------
 1           | SATA SAS
 2           | SATA SAS

我尝试将distinct 放在string_agg 前面,但是没有用。

Here's a db-fiddle.

关键字“distinct”附近的语法不正确。

【问题讨论】:

标签: sql sql-server


【解决方案1】:

string_agg 缺少该功能,因此您必须准备所需的不同列表,然后将它们聚合:

select id , string_agg(interface,' ') hard_disk_interfaces
from (
   select distinct c.id, interface
   from Computer c
   left join HardDisk hd on c.Id = hd.ComputerId
) t group by id

对于您的原始查询:

select *
from ....
join (
 <query above> ) as temp 
...
group by ... , hard_disk_interfaces

【讨论】:

  • 谢谢@eshirvana,虽然这适用于我的简化方案,但当我实际尝试使其在我的actual query 中工作时,它似乎并没有这样做。我仍然得到重复。寻找temp,我已经在inner join 中尝试过,因为它必须适合所有其他连接。
  • @J86 看起来你的查询可以使用大量的窗口函数和OUTER APPLY,这会减少大小并加快速度,并且可能会摆脱如果您使用一些实际数据创建dbfiddle.uk,我们可以看到可以做什么
  • Microsoft SQL Server 2017 (RTM-GDR) (KB4583456) - 14.0.2037.2 (X64) Nov 2 2020 19:19:59 Copyright (C) 2017 Microsoft Corporation Standard Edition (64-bit) on Windows Server 2019 Standard 10.0 (Build 17763: ) 是否支持窗口函数我可以尝试用一些数据创建一个小提琴,这需要一段时间,因为表太多了
  • @J86 是的,一定要准备一把小提琴
【解决方案2】:

其他几种方式:

;WITH cte AS 
(
  SELECT c.Id, Interface = CONVERT(varchar(max), hd.Interface)
    FROM dbo.Computer AS c
    LEFT OUTER JOIN dbo.HardDisk AS hd ON c.Id = hd.ComputerId
    GROUP BY c.Id, hd.Interface
)
SELECT Id, STRING_AGG(Interface, ' ')
FROM cte
GROUP BY Id;

SELECT c.Id, STRING_AGG(x.Interface, ' ')
FROM dbo.Computer AS c
OUTER APPLY
(
  SELECT Interface = CONVERT(varchar(max), Interface) 
    FROM dbo.HardDisk WHERE ComputerID = c.Id
    GROUP BY Interface
) AS x
GROUP BY c.Id;

如果您在具有更多连接的更大查询中获得重复,我认为这些重复不是来自STRING_AGG()的重复,而是重复的来自 47 个连接中的一个或多个,而不是来自查询的这一部分。而且我猜即使你完全忽略了这个连接,你仍然会得到那些重复。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-25
    • 2017-04-05
    • 1970-01-01
    • 2013-07-18
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 2013-12-20
    相关资源
    最近更新 更多