聚合函数中的多个列,但仅适用于与WHERE子句匹配的行

时间:2018-01-12 23:45:00

标签: sql sql-server tsql

示例数据集:

+----------+---------+-----+
| order_id | prod_id | qty |
+----------+---------+-----+
|        1 |       1 |   2 |
|        1 |       1 |   4 |
|        1 |       3 |   1 |
|        2 |       1 |   1 |
|        2 |       2 |   2 |
|        3 |       4 |   1 |
|        3 |       4 |   2 |
|        3 |       2 |   3 |
|        3 |       3 |   5 |
|        4 |       1 |   2 |
|        4 |       2 |   3 |
|        4 |       3 |   3 |
|        4 |       4 |   3 |
|        4 |       6 |   2 |
+----------+---------+-----+

我要做的是构建一个“报告”视图,该视图将根据产品代码聚合某些总计。因此,例如,我想要一个列按产品代码1的顺序排列,另一个列具有产品2和3的总计,一个产品代码4和6。

请注意,产品代码的值来自产品类表,因此我实际上希望获得第1类中的所有产品,即产品1,然后是第2类中的所有产品,这将是产品2和3,然后是第3类中的所有产品,即产品4和6。

+----------+--------+--------+--------+
| order_id | c1_tot | c2_tot | c3_tot |
+----------+--------+--------+--------+
|        1 |      6 |      1 |      0 |
|        2 |      1 |      2 |      0 |
|        3 |      0 |      8 |      3 |
|        4 |      2 |      6 |      5 |
+----------+--------+--------+--------+

我可以使用WHERE子句为一列执行此操作:

SELECT 
    [order_id],
    SUM([qty]) AS [c2]
FROM [orders]
WHERE [prod_id] IN (SELECT [id] FROM [product_class] WHERE [class] = 2)
GROUP BY [order_id]

我提出的另一种方法是存储函数,但这似乎是一种冗长的方式:

SELECT DISTINCT
    [order_id],
    total_products_by_class([order_id],1) AS [c1_tot],
    total_products_by_class([order_id],2) AS [c2_tot],
    total_products_by_class([order_id],3) AS [c3_tot]
FROM [orders]

我怀疑理论上可以用分析函数完成某些事情吗?...

有没有办法在没有适合视图的存储函数的情况下执行此操作?

更新:更清楚地了解是否需要从子查询中提取产品的值。

2 个答案:

答案 0 :(得分:0)

CASE语句可能是您在简单查询中需要执行的操作。

df['TOTAL']=(df.index.get_level_values('POP')*df['PERCENT']).values
df
Out[874]: 
                       PERCENT  TOTAL
DATE       POP SEX                   
2015-01-01 100 MALE       0.51   51.0
               FEMALE     0.49   49.0
2016-01-01 120 Male       0.52   62.4
               FEMALE     0.48   57.6

答案 1 :(得分:0)

我获取了为orders表提供的示例数据,并根据问题第2段中的描述创建了product_class表。

示例数据:

create table #orders
    (
        order_id int
        , prod_id int
        , qty int
    )

create table #product_class
    (
        id int
        , class int
    )

insert into #orders
values (1, 1, 2)
    , (1, 1, 4)
    , (1, 3, 1)
    , (2, 1, 1)
    , (2, 2, 2)
    , (3, 4, 1)
    , (3, 4, 2)
    , (3, 2, 3)
    , (3, 3, 5)
    , (4, 1, 2)
    , (4, 2, 3)
    , (4, 3, 3)
    , (4, 4, 3)
    , (4, 6, 2)

insert into #product_class
values (1, 1)
    , (2, 2)
    , (3, 2)
    , (4, 3)
    , (6, 3)

<强>答案:

从问题中写的第一个查询作为灵感开始,我将对product_class表的引用更改为inner join,并将class添加到group by。在此之后,所有需要进行的操作都是pivot,以使class es跨越列而不是行。

select b.order_id
, isnull(b.[1], 0) as c1_tot
, isnull(b.[2], 0) as c2_tot
, isnull(b.[3], 0) as c3_tot
from (
    SELECT o.[order_id]
    , pc.class
    , SUM(o.[qty]) AS [c2]
    FROM [#orders] as o
    inner join #product_class as pc on o.prod_id = pc.id
    GROUP BY o.[order_id]
    , pc.class
    ) as a
pivot (max(a.c2) for a.class in ([1], [2], [3])) as b

输出完全匹配所需的输出。