【问题标题】:Unique values with string_agg on more than 1 column超过 1 列具有 string_agg 的唯一值
【发布时间】:2020-05-02 03:56:40
【问题描述】:

我正在尝试分组并获取多列的值列表。这是一个例子:

City   | State | Income
-------+-------+--------
Salem  |  OH   | 40000
Salem  |  OH   | 45000
Mason  |  OH   | 50000
Dayton |  OH   | 60000
Salem  |  MA   | 40000
Mason  |  MA   | 45000
Mason  |  MA   | 50000
Dayton |  MA   | 70000
Salem  |  PA   | 45000
Mason  |  PA   | 50000
Dayton |  PA   | 60000

我要找的结果是:

City   |  States    | Income
-------+------------+--------------
Salem  | OH,MA,PA   | 40000,45000
Mason  | OH,MA,PA   | 50000,45000
Dayton | OH,MA,PA   | 60000,70000

我设法做到了这一点:

City   |  States    | Income
-------+------------+-------------------------
Salem  | OH,MA,PA   | 40000,40000,45000,45000
Mason  | OH,MA,PA   | 50000,50000,50000,45000
Dayton | OH,MA,PA   | 60000,70000,60000

我如何从这里到结果集?

City   |  States    | Income
-------+------------+-------------------------
Salem  | OH,MA,PA   | 40000,45000,50000
Mason  | OH,MA,PA   | 50000,45000
Dayton | OH,MA,PA   | 60000,70000

【问题讨论】:

  • 向我们展示您当前的尝试。另外,你没有收入50000 城市Salem

标签: sql sql-server tsql azure-sql-database


【解决方案1】:

唉,您不能将string_agg()distinct 一起使用。但是你可以使用条件聚合:

select city,
       string_agg(case when seqnum_state = 1 then state end, ',') as states,
       string_agg(case when seqnum_income = 1 then income end, ',') as incomes
from (select t.*,
             row_number() over (partition by city, state order by state) as seqnum_state,
             row_number() over (partition by city, income order by income) as seqnum_income
      from t
     ) t
group by city;

Here 是一个 dbfiddle。

【讨论】:

  • 我真的希望 MS 支持 distinct。您的回答简短而优雅。感谢您的帮助!
【解决方案2】:

您可以对 (City, state) 和 (City, Income) 执行单独的分组以删除重复项,然后您可以分别构建 (States) 和 (Incomes) 聚合字符串,最后您可以将结果合并为一个表:

DECLARE @tmp TABLE (City VARCHAR(100), State VARCHAR(100), Income int);
INSERT INTO @tmp
VALUES ('Salem' ,'OH', 40000)   ,('Salem' ,'OH', 45000) ,('Mason' ,'OH', 50000) 
      ,('Dayton','OH', 60000)   ,('Salem' ,'MA', 40000) ,('Mason' ,'MA', 45000)
      ,('Mason' ,'MA', 50000)   ,('Dayton','MA', 70000) ,('Salem' ,'PA', 45000) 
      ,('Mason' ,'PA', 50000)   ,('Dayton','PA', 60000)

;with States as(
    select City, state
    from @tmp
    group by  City, state
),
incomes as(
    select City, Income
    from @tmp
    group by  City, Income
)
, states_g as ( 
    select city, STRING_AGG(state,',') as States  
    from states
    group by city
)
, incomes_g as ( 
    select city, STRING_AGG(Income,',') as Incomes  
    from incomes
    group by city
)
select 
    s.City, s.States, i.Incomes 
    from 
        states_g as s
            inner join
        incomes_g as i
            on i.City = s.City

结果:

【讨论】:

  • 谢谢,它似乎返回了我正在寻找的结果。戈登有不同而简洁的答案。有一个伟大的!
【解决方案3】:

这里还有另一种方法 (db fiddle):

select city,
       (select string_agg(value,', ') from (select distinct value from string_split(string_agg(state, ','),',')) t) as states,
       (select string_agg(value,', ') from (select distinct value from string_split(string_agg(income, ','),',')) t) as incomes
from t
group by city;

您可以轻松地将拆分和合并部分转换为可重用的标量值函数。

欢迎专家对性能发表评论。

【讨论】:

    猜你喜欢
    • 2011-09-11
    • 2021-12-23
    • 1970-01-01
    • 2019-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多