【问题标题】:Full Outer Join, Coalesce, and Group By (Oh My!)完全外连接、合并和分组(哦,我的!)
【发布时间】:2018-11-20 00:26:24
【问题描述】:

我将分两部分问这个问题,因为我的逻辑可能有问题,如果是这样,语法就无关紧要了。

  1. 我有 10 个查询。每个查询都返回月份、供应商和计数(一些指标)。查询使用各种表、连接等。并非所有月份/供应商组合都存在于每个查询的输出中。我想将这些组合成一个可以在 Excel 中导出和透视的数据集。

我希望输出如下所示:

Month | Supplier | Metric1 |Metric2 |..| Metric 10
2018-01 | Supp1 | _value_ | _value_ |...| _value_ |
2018-01 | Supp2 | NULL | _value_ |...| NULL

实现此目的最好/最简单/最有效的方法是什么?

  1. 我尝试了各种方法来完成上述操作,但我似乎无法完全正确地理解语法。我想制作一个非常简单的测试用例并以此为基础,但我对数据库只有选择权限,所以我无法对其进行测试。我能够创建一个查询,该查询至少不会导致任何弯曲的红色错误行,但是将相同的逻辑应用于更大的问题是行不通的。

这就是我所拥有的:

 create table test1(name varchar(20),credit int);
 insert into test1 (name, credit) values ('Ed',1),('Ann',1),('Jim',1),('Ed',1),('Ann',1);
 create table test2 (name varchar(10), debit int);
 insert into test2 (name, debit) values ('Ann',1),('Sue',1),('Sue',1),('Sue',1);

 select
    coalesce(a.name, b.name) as name,
    cred,
    deb
 from
    (select name, count(credit) as cred
        from test1 
        group by name) a
    full outer join 
    (select name, count(debit) as deb
        from test2
        group by name) b  on 
     a.name =b.name;

我走对了吗?

更新:根据 Gordon 的输入,我对前两个查询进行了尝试:

select Month, Supp,
    sum(case when which = 1 then metric end) as Exceptions,
    sum(case when which = 2 then metric end) as BackOrders
from (
        (
         select Month, Supp, metric, 1 as which
         from (
                select (convert(char(4),E.PostDateTime,120)+'-'+convert(char(2),E.PostDateTime,101)) as Month, E.TradingPartner as Supp, count(distinct(E.excNum)) as metric
                from db..TrexcMangr E
                where (E.DSHERep in ('AVR','BTB') OR E.ReleasedBy in ('AVR','BTB')) AND year(E.PostDateTime) >= '2018'
              ) a
         )

         union all

        (
         select Month, Supp, metric, 2 as which
         from (
                select (convert(char(4),T.UpdatedDateTime,120)+'-'+convert(char(2),T.UpdatedDateTime,101)) as Month, P.Supplier as Supp, count(*) as metric
                from db1..trordertext T
                    inner join mdid_Tran..trOrderPO P on P.PONum = T.RefNum
                where T.TextType = 'BO' AND (T.CreatedBy in ('AVR','BTB') OR T.UpdatedBy in ('AVR','BTB')) AND year(UpdatedDateTime) >=2018
              ) b
        )
     ) q
group by Month, Supp

...但我得到了一个错误的组。

【问题讨论】:

  • 查看完整、准确、实际的错误会很有帮助。
  • 另外,尽量不要使用列名Month。由于存在 MONTH() 函数,它会导致混淆。您可以使用[Month],但在正常实践中最好避免使用现有关键字作为列名;也许使用sMonth,因为您将所有内容都作为字符串进行操作? (也就是说,使用字符串来操作和表示日期通常是个坏主意。)
  • 您是否故意在子查询中不包含GROUP BY?这对我来说似乎是一个错误......
  • group by 错误是什么?
  • 如果您添加了一个聚合函数,例如 count(*),那么您还需要对您选择的列进行 GROUP BY。 (如果未在聚合函数中使用)

标签: sql sql-server group-by coalesce full-outer-join


【解决方案1】:

一种方法使用union allgroup by

select month, supplier,
       sum(case when which = 1 then metric end) as metric_01,
       sum(case when which = 2 then metric end) as metric_02,
       . . .
from ((select Month, Supplier, Metric, 1 as which
       from (<query1>) q
       . . .
      ) union all
      (select Month, Supplier, Metric, 2 as which
       from (<query2>) q
       . . .
      ) union all
      . . .
     ) q
group by month, supplier;

【讨论】:

  • 我想我可能把问题简单化了。在每个表中,月份和供应商列并不总是被称为相同的东西。我在前两个查询中尝试了你的建议,但我得到了一个错误的组。
  • @sandeaj - 没关系。使用别名将列“重命名”为标准化列名...(SELECT mmm AS month, Supp AS supplier, Metric, 1 AS which FROM source1) (假设列具有相同的数据类型、格式等,只是名称不同...)
  • 使用联合时,只有第一个查询的名称很重要。借调的联合查询甚至不必有名称。但它确实需要以与第一个查询相同的顺序返回相同的数据类型。
【解决方案2】:
SELECT
    CalendarMonthStart,
    Supp,
    SUM(CASE WHEN metric_id = 1 THEN metric END) as Exceptions,
    SUM(CASE WHEN metric_id = 2 THEN metric END) as BackOrders
FROM
(
    SELECT
        DATEADD(month, DATEDIFF(month, 0, E.PostDateTime), 0)   AS CalendarMonthStart,
        E.TradingPartner            AS Supp,
        COUNT(DISTINCT(E.excNum))   AS metric,
        1                           AS metric_id
    FROM
        db..TrexcMangr E
    WHERE
        (      E.DSHERep    in ('AVR','BTB')
            OR E.ReleasedBy in ('AVR','BTB')
        )
        AND E.PostDateTime >= '2018-01-01'
    GROUP BY
        1, 2

    UNION ALL

    SELECT
        DATEADD(month, DATEDIFF(month, 0, T.UpdatedDateTime), 0)   AS CalendarMonthStart,
        T.UpdatedDateTime,
        P.Supplier                  AS Supp,
        COUNT(*)                    AS metric,
        2                           AS metric_id
    FROM
        db1..trordertext T
    INNER JOIN
        mdid_Tran..trOrderPO P
            ON  P.PONum = T.RefNum
    WHERE
        (      T.CreatedBy in ('AVR','BTB')
            OR T.UpdatedBy in ('AVR','BTB')
        )
        AND T.TextType = 'BO'
        AND T.UpdatedDateTime >= '2018-01-01'
    GROUP BY
        1, 2
)
   combined
GROUP BY
    CalendarMonthStart,
    Supp

【讨论】:

    猜你喜欢
    • 2014-09-23
    • 2017-06-09
    • 2017-09-12
    • 2015-11-15
    • 2017-07-05
    • 1970-01-01
    • 1970-01-01
    • 2016-12-19
    • 2017-03-05
    相关资源
    最近更新 更多