3

我正在对多个记录执行聚合函数,这些记录按公共 ID 分组。问题是,我还想导出一些其他字段,这些字段在分组记录中可能不同,但我想从其中一个记录中获取这些特定字段(第一个,根据查询的 ORDER BY)。

起点示例:

SELECT
  customer_id,
  sum(order_total),
  referral_code
FROM order
GROUP BY customer_id
ORDER BY date_created

我需要查询推荐代码,但在聚合函数之外执行此操作意味着我也必须按该字段进行分组,这不是我想要的 - 在此示例中,我需要每个客户恰好一行。我真的只关心第一个订单的推荐代码,我很乐意丢弃任何以后的推荐代码。

这是在 PostgreSQL 中,但可能来自其他数据库的语法可能足够相似以工作。

被拒绝的解决方案:

  • 不能使用 max() 或 min() 因为顺序很重要。
  • 子查询一开始可能会起作用,但不能扩展;这是一个极其简化的例子。我的实际查询有几十个字段,比如我只想要第一个实例的参考代码,以及几十个 WHERE 子句,如果在子查询中重复,将成为维护的噩梦。
4

6 回答 6

1

嗯,其实很简单。

首先,让我们编写一个将进行聚合的查询:

select customer_id, sum(order_total)
from order
group by customer_id

现在,让我们编写一个查询,该查询将返回给定 customer_id 的 1strefer_code 和 date_created:

select distinct on (customer_id) customer_id, date_created, referral_code
from order
order by customer_id, date_created

现在,您可以简单地加入 2 个选择:

select
    x1.customer_id,
    x1.sum,
    x2.date_created,
    x2.referral_code
from
    (
        select customer_id, sum(order_total)
        from order
        group by customer_id
    ) as x1
    join
    (
        select distinct on (customer_id) customer_id, date_Created, referral_code
        from order
        order by customer_id, date_created
    ) as x2 using ( customer_id )
order by x2.date_created

我没有测试它,所以它可能有错别字,但通常它应该可以工作。

于 2009-05-04T21:55:46.850 回答
0

您将需要窗口函数。这是一种 GROUP BY,但您仍然可以访问各个行。虽然只使用了 Oracle 等价物。

于 2009-05-04T20:21:43.567 回答
0

也许是这样的:

SELECT
     O1.customer_id,
     O1.referral_code,
     SQ.total
FROM
     Orders O1
LEFT OUTER JOIN Orders O2 ON
     O2.customer_id = O1.customer_id AND
     O2.date_created < O1.date_created
INNER JOIN (
     SELECT
          customer_id,
          SUM(order_total) AS total
     FROM
          Orders
     GROUP BY
          customer_id
     ) SQ ON SQ.customer_id = O1.customer_id
WHERE
     O2.customer_id IS NULL
于 2009-05-04T20:34:40.667 回答
0

如果 date_created 保证每个 customer_id 都是唯一的,那么您可以这样做:

[简单表]

create table ordertable (customer_id int, order_total int, referral_code char, date_created datetime)
insert ordertable values (1,10, 'a', '2009-01-01')
insert ordertable values (2,15, 'b', '2009-01-02')
insert ordertable values (1,35, 'c', '2009-01-03')

[用更好的东西替换我蹩脚的表名:)]

SELECT
  orderAgg.customer_id,
  orderAgg.order_sum,
  referral.referral_code as first_referral_code
FROM (
        SELECT
          customer_id,
          sum(order_total) as order_sum
        FROM ordertable
        GROUP BY customer_id
    ) as orderAgg join (
        SELECT
          customer_id,
          min(date_created) as first_date
        FROM ordertable
        GROUP BY customer_id
    ) as dateAgg on orderAgg.customer_id = dateAgg.customer_id
    join ordertable as referral 
        on dateAgg.customer_id = referral.customer_id
            and dateAgg.first_date = referral.date_created
于 2009-05-04T20:40:20.777 回答
0

这样的事情会奏效吗?

SELECT
  customer_id,
  sum(order_total),
  (SELECT referral_code 
   FROM order o 
   WHERE o.customer_id = order.customer_id 
   ORDER BY date_created 
   LIMIT 1) AS customers_referral_code
FROM order
GROUP BY customer_id, customers_referral_code
ORDER BY date_created

这不需要您在两个地方维护 WHERE 子句并保持顺序重要性,但如果您需要“数十个字段”,例如referral_code,就会变得非常麻烦。它也相当慢(至少在 MySQL 上)。

在我看来referral_code,这几十个字段应该在客户表中,而不是订单表中,因为它们在逻辑上与客户 1:1 相关联,而不是订单。将它们移到那里将使查询更简单。

这也可以解决问题:

SELECT
  o.customer_id,
  sum(o.order_total),
  c.referral_code, c.x, c.y, c.z
FROM order o LEFT JOIN (
    SELECT referral_code, x, y, z
    FROM orders c 
    WHERE c.customer_id = o.customer_id 
    ORDER BY c.date_created
    LIMIT 1
) AS c
GROUP BY o.customer_id, c.referral_code
ORDER BY o.date_created
于 2009-05-04T23:00:00.877 回答
0
SELECT  customer_id, order_sum,
        (first_record).referral, (first_record).other_column
FROM    (
        SELECT  customer_id,
                SUM(order_total) AS order_sum,
                (
                SELECT  oi
                FROM    order oi
                WHERE   oi.customer_id = o.customer_id
                LIMIT 1
                ) AS first_record
        FROM    order o
        GROUP BY
                customer_id
        ) q
于 2009-05-05T15:16:05.273 回答