【问题标题】:Aggregate without duplicates聚合无重复
【发布时间】:2020-02-09 19:27:04
【问题描述】:

我在这里做的是:

表 1:AOC_Model

AOC_ID int (Primary Key)
Model varchar(50)

表 2:AOC_Chipset

AOC_CHIPSET_ID int (Primary Key)
CONTROLLER_ID int
CHIPSET_ID int
AOC_ID int

表 3:控制器

CONTROLLER_ID int (Primary Key)
CONTROLLER varchar(10)

表 4:芯片组

CONTROLLER_ID int (Primary Key)
CHIPSET_ID int (Primary Key)
CHIPSET varchar(50)

表 5:Notes_Chipset

NOTES_CHIPSET_ID int (Primary Key)
CONTROLLER_ID int
CHIPSET_ID int
DATE date
NOTES varchar(800)

首先我有一个通过 Controller_ID 连接到控制器的芯片组表 然后我有 AOC_Chipset,它实际上充当控制器和芯片组之间的连接表。 AOC_Chipset 通过 Controller_ID 和 Chipset_id 加入 Chipset 然后我有 Notes_Chipset,它也通过 Controller_ID 和 Chipset_id 加入到 Chipset 最后,我有通过 AOC_ID 加入 AOC_Chipset 的 AOC_Model

我在这里有很多对很多的关系。 我可以将一个或两个控制器分配给相同的 AOC_ID。 我可以将一两个芯片组分配给同一个控制器。 我可以将多个笔记分配给同一个芯片组。

我在 SQL Server 2019 中创建了这个查询:

SELECT
    dbo.AOC_CHIPSET.AOC_ID, 
    string_agg(dbo.CONTROLLER.CONTROLLER, ', ') AS vControllers, 
    string_agg(dbo.CHIPSET.CHIPSET, ', ') AS vChipsets, 
    string_agg(dbo.NOTES_CHIPSET.DATE, ', ') AS vDate,
    string_agg(dbo.NOTES_CHIPSET.NOTES, ', ') AS vNotes
FROM
    dbo.AOC_CHIPSET 
INNER JOIN 
    dbo.CHIPSET ON dbo.AOC_CHIPSET.CONTROLLER_ID = dbo.CHIPSET.CONTROLLER_ID 
                AND dbo.AOC_CHIPSET.CHIPSET_ID = dbo.CHIPSET.CHIPSET_ID 
INNER JOIN 
    dbo.CONTROLLER ON dbo.CHIPSET.CONTROLLER_ID = dbo.CONTROLLER.CONTROLLER_ID 
INNER JOIN 
    dbo.NOTES_CHIPSET ON dbo.CHIPSET.CONTROLLER_ID = dbo.NOTES_CHIPSET.CONTROLLER_ID  
                      AND dbo.CHIPSET.CHIPSET_ID = dbo.NOTES_CHIPSET.CHIPSET_ID 
                      AND dbo.CONTROLLER.CONTROLLER_ID = dbo.NOTES_CHIPSET.CONTROLLER_ID
GROUP BY 
    dbo.AOC_CHIPSET.AOC_ID

问题是结果包含重复项

我知道我可以使用DISTINCT,但我不知道在哪里/如何将它与string_agg 结合使用?

【问题讨论】:

  • 示例数据和所需输出将很有用! Please do not post image of data
  • 您能否详细介绍一下您的架构。特别是,重要的是要知道所有这些表中哪些列组合是唯一键或主键。
  • 不确定我在问题中添加的内容是否足够好。我不想听起来令人困惑,也不想在不提供图片(如图表)或示例代码的情况下不确定如何更好地解释。看起来两者都不可接受,因为上面提到的人不发布图片:-(
  • 感谢您提供更多信息。我的答案中的 SQL 有帮助吗?

标签: sql-server string-aggregation


【解决方案1】:

我用直接放在选择列表中的子选择替换了连接。这允许我为每个检索到的属性选择不同的值。事实上,每个字符串总是有 2 个子选择要创建。内部的有SELECT DISTINCT,外部的有string_agg。内部子选择使用 WHERE 子句过滤其行,其中 AOC_ID 匹配主 SELECT

SELECT
    ac.AOC_ID,
    (SELECT string_agg(CONTROLLER, ', ') FROM
      (SELECT DISTINCT CONTROLLER
       FROM dbo.CONTROLLER co INNER JOIN dbo.AOC_CHIPSET ac1
          ON ac1.CONTROLLER_ID = co.CONTROLLER_ID
       WHERE ac1.AOC_ID = ac.AOC_ID) x) AS vControllers,
    (SELECT string_agg(CHIPSET, ', ') FROM
      (SELECT DISTINCT CHIPSET
       FROM dbo.CHIPSET cs INNER JOIN dbo.AOC_CHIPSET ac2 
          ON ac2.CONTROLLER_ID = cs.CONTROLLER_ID AND ac2.CHIPSET_ID = cs.CHIPSET_ID
       WHERE ac2.AOC_ID = ac.AOC_ID) y) AS vChipsets,
    (SELECT string_agg([DATE], ', ') FROM
      (SELECT DISTINCT [DATE]
       FROM dbo.NOTES_CHIPSET nd INNER JOIN dbo.AOC_CHIPSET ac3
          ON ac3.CONTROLLER_ID = nd.CONTROLLER_ID AND ac3.CHIPSET_ID = nd.CHIPSET_ID
       WHERE ac3.AOC_ID = ac.AOC_ID) z) AS vDate,
    (SELECT string_agg(NOTES, ', ') FROM
      (SELECT DISTINCT NOTES
       FROM dbo.NOTES_CHIPSET nd INNER JOIN dbo.AOC_CHIPSET ac4
          ON ac4.CONTROLLER_ID = nd.CONTROLLER_ID AND ac4.CHIPSET_ID = nd.CHIPSET_ID
       WHERE ac4.AOC_ID = ac.AOC_ID) z) AS vNotes
FROM
    dbo.AOC_CHIPSET ac
GROUP BY
    ac.AOC_ID

子查询中的SELECT DISTINCT 有效,因为选择列表不包含任何控制器或芯片组ID。这对于外部级别的连接是不可能的,因为它们需要这些 id。

【讨论】:

  • 好的,现在我在我的 SQL-Server 上使用您添加到问题中的架构创建了一个示例后,完全修改了我的答案。
  • 为了提高可见性,我正在考虑删除 vDate 列,并可能使用 Date 作为 vNotes 下的分隔符。在 vNotes 下实现这样的事情是否容易,其中每个日期都以新行项目开头,后跟“:”空格和评论。我想让它看起来像这样:link。我想不出如何完成这项任务的方法
  • 当然可以;但是,就个人而言,我更喜欢在报告生成器中做这些高级的事情,而不是在 SQL 中。在 SQL 中,您必须将注释子查询集成到日期子查询中:SELECT string_agg([DATE], ', ') + ': ' + (<notes sub-query here>) FROM ...,其中注释子查询在 WHERE 子句中还具有日期条件。但是,随着所有这些子子查询,这往往变得越来越不可读。
  • 好的...谢谢您的信息
【解决方案2】:

我不完全理解这个查询的目的/用途是什么,如果这没有帮助,请原谅我。但我认为 DISTINCT 对您没有多大用处,因为您的 AOC_ID 在重复数据的每一行中都是唯一值。如果您摆脱了 AOC_ID,那么您可以使用 DISTINCT 而不必担心该数据会出现两次。但是同样,如果在这个查询中摆脱 AOC_ID 不是一个选项,我和你一样难过。

【讨论】:

  • 您只需要选择一个具有聚合度量 MAX/MIN 的值。请参阅建议的答案。
【解决方案3】:
SELECT MAX(AOC_ID) as AOC_ID, vControllers, vChipsets, vDate, vNotes FROM
(
 SELECT
    dbo.AOC_CHIPSET.AOC_ID, 
    string_agg(dbo.CONTROLLER.CONTROLLER, ', ') AS vControllers, 
    string_agg(dbo.CHIPSET.CHIPSET, ', ') AS vChipsets, 
    string_agg(dbo.NOTES_CHIPSET.DATE, ', ') AS vDate,
    string_agg(dbo.NOTES_CHIPSET.NOTES, ', ') AS vNotes
FROM
    dbo.AOC_CHIPSET 
INNER JOIN 
    dbo.CHIPSET ON dbo.AOC_CHIPSET.CONTROLLER_ID = dbo.CHIPSET.CONTROLLER_ID 
                AND dbo.AOC_CHIPSET.CHIPSET_ID = dbo.CHIPSET.CHIPSET_ID 
INNER JOIN 
    dbo.CONTROLLER ON dbo.CHIPSET.CONTROLLER_ID = dbo.CONTROLLER.CONTROLLER_ID 
INNER JOIN 
    dbo.NOTES_CHIPSET ON dbo.CHIPSET.CONTROLLER_ID = dbo.NOTES_CHIPSET.CONTROLLER_ID  
                      AND dbo.CHIPSET.CHIPSET_ID = dbo.NOTES_CHIPSET.CHIPSET_ID 
                      AND dbo.CONTROLLER.CONTROLLER_ID = dbo.NOTES_CHIPSET.CONTROLLER_ID
GROUP BY 
    dbo.AOC_CHIPSET.AOC_ID
) R
GROUP BY vControllers, vChipsets, vDate, vNotes

【讨论】:

    猜你喜欢
    • 2016-10-21
    • 1970-01-01
    • 2018-05-17
    • 2021-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多