【问题标题】:How can I combine the two select queries on the same table horizontally in Postgresql?如何在 Postgresql 中水平组合同一张表上的两个选择查询?
【发布时间】:2019-10-07 04:49:45
【问题描述】:

每个人。我是 Postgresql 的初学者。最近我遇到了一个问题。 我有一张名为“sales”的表。

create table sales
    (
        cust    varchar(20),
        prod    varchar(20),
        day integer,
        month   integer,
        year    integer,
        state   char(2),
        quant   integer
    );
insert into sales values ('Bloom', 'Pepsi', 2, 12, 2001, 'NY', 4232);
insert into sales values ('Knuth', 'Bread', 23, 5, 2005, 'PA', 4167);
insert into sales values ('Emily', 'Pepsi', 22, 1, 2006, 'CT', 4404);
insert into sales values ('Emily', 'Fruits', 11, 1, 2000, 'NJ', 4369);
insert into sales values ('Helen', 'Milk', 7, 11, 2006, 'CT', 210);
insert into sales values ('Emily', 'Soap', 2, 4, 2002, 'CT', 2549);
insert into sales values ('Bloom', 'Eggs', 30, 11, 2000, 'NJ', 559);

.... 总共有 498 行。 以下是该表的概述:

现在我想计算每种产品的最大和最小销售量,以及它们对应的客户(购买该产品的人)、日期(即最大和最小销售量的日期)以及销售所在的州发生了交易。 以及相应产品的平均销量。

组合起来应该是这样的:

它应该有 10 行,因为总共有 10 个不同的产品。

我试过了:

select prod,
       max(quant),
       cust as MAX_CUST
from sales
group by prod;

但它返回了一个错误,并说客户应该在 group by 中。但我只想按产品类型分类。

此外,我怎样才能将 ma​​x_q 及其客户、日期、状态min_q 及其客户、日期、状态 以及 AVG_Q 通过他们的产品名称? 我真的感到很困惑!

【问题讨论】:

  • 对于未来的问题:样本数据最好显示为formatted text。请参阅here,了解有关如何创建漂亮表格的一些提示。

标签: postgresql join pivot subquery inner-join


【解决方案1】:

您可以使用分析函数ROW_NUMBER通过增加/减少子查询中每个产品的销售额来对记录进行排名,然后进行条件聚合:

SELECT
    prod product,
    MAX(CASE WHEN rn2 = 1 THEN quant END) max_quant,
    MAX(CASE WHEN rn2 = 1 THEN cust END) max_cust,
    MAX(CASE WHEN rn2 = 1 THEN TO_DATE(year || '-' || month || '-' || day, 'YYYY-MM-DD') END) max_date,
    MAX(CASE WHEN rn2 = 1 THEN state END) max_state,
    MAX(CASE WHEN rn1 = 1 THEN quant END) min_quant,
    MAX(CASE WHEN rn1 = 1 THEN cust END) min_cust,
    MAX(CASE WHEN rn1 = 1 THEN TO_DATE(year || '-' || month || '-' || day, 'YYYY-MM-DD') END) min_date,
    MAX(CASE WHEN rn1 = 1 THEN state END) min_state,
    avg_quant
FROM (
    SELECT
        s.*,
        ROW_NUMBER() OVER(PARTITION BY prod ORDER BY quant) rn1,
        ROW_NUMBER() OVER(PARTITION BY prod ORDER BY quant DESC) rn2,
        AVG(quant) OVER(PARTITION BY prod) avg_quant
    FROM sales s
) x
WHERE rn1 = 1 OR rn2 = 1
GROUP BY prod, avg_quant

【讨论】:

  • 非常感谢您的帮助!!!我删除了“s”。从“s.*”开始,并在 avg(quant) 中添加了一个 round(),它最终输出了我想要的结果。你能告诉我为什么“s.*”不起作用,这是什么类型的语法????
  • @WikizVito: s 只是sales 表的别名。我刚刚更新了查询(没有声明别名),它应该可以正常工作了。
  • 好的,谢谢!为什么我不能使用round()得到avg(quant)的整数?
  • @WikizVito: round() 将按预期工作,如下所示:ROUND(AVG(quant) OVER(PARTITION BY prod)) avg_quant
  • 是的,你是对的!我弄错了右括号的位置。谢谢!
【解决方案2】:

在列上应用两个聚合函数(最小值,最大值)并选择相应的行并不是那么简单。如果您只想要一个聚合函数,您可以使用密集等级(窗口函数)执行下面的示例。

SELECT prod, quant cust,
    dense_rank() OVER (PARTITION BY prod ORDER BY quant DESC) AS c_rank
FROM sales WHERE c_rank < 2;

这将为您提供最大 quant 的产品行。你可以对最小量化做同样的事情。在同一个查询中执行这两个操作会更加复杂,您可以通过简单的方式为每个案例创建动态表并加入它们,如下所示。

with max_quant as (
SELECT prod, quant cust,
    dense_rank() OVER (PARTITION BY prod ORDER BY quant DESC) AS c_rank
FROM sales WHERE c_rank < 2
),
min_quant as (
SELECT prod, quant cust,
    dense_rank() OVER (PARTITION BY prod ORDER BY quant DESC) AS c_rank
FROM sales WHERE c_rank < 2
),
avg_quant as (
select prod, avg(quant) as avg_quant from sales group by prod
)

select mx.prod, mx.quant, mx.cust, mn.quant, mn.cust, ag.avg_quant
from max_quant mx 
join min_quant mn on mn.prod = mx.prod
join avg_quant ag on ag.prod = mx.prod;

您不能在此处使用group by 来选择最小值/最大值,因为您想获得 quant 的最小值/最大值的完整行,而这无法直接使用 group by

【讨论】:

  • 首先非常感谢您的帮助。我跑了SELECT prod, quant cust dense_rank() OVER (PARTITION BY prod ORDER BY quant DESC) AS c_rank FROM sales WHERE c_rank &lt; 2; 但是,它仍然说语法错误是围绕dense_rank()...
  • 所选字段之间缺少逗号。更新后的查询将是 SELECT prod, quant ,cust ,dense_rank() OVER (PARTITION BY prod ORDER BY quant DESC) AS c_rank FROM sales WHERE c_rank &lt; 2;
猜你喜欢
  • 1970-01-01
  • 2012-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-14
  • 2016-11-10
相关资源
最近更新 更多