6

我有以下选择,其目标是选择自 X 日以来没有销售的所有客户,并带上最后一次销售的日期和销售次数:

select s.customerId, s.saleId, max (s.date) from sales s
group by s.customerId, s.saleId
having max(s.date) <= '05-16-2013'

但是这种方式给我带来了以下信息:

19 | 300 | 26/09/2005
19 | 356 | 29/09/2005
27 | 842 | 10/05/2012

换句话说,前两行来自同一个客户(id 19),我希望他为每个客户只获得一条记录,这将是最大日期的记录,在这种情况下,第二条记录来自此列表。按照这种逻辑,我应该从“group by”子句中删除 s.saleId,但如果我这样做了,我当然会得到错误:选择列表中的无效表达式(不包含在聚合函数或 GROUP BY 中条款)。

我正在使用火鸟 1.5

我怎样才能做到这一点?

4

4 回答 4

9

GROUP BY 通过聚合一组行来汇总数据,每组返回一行。您正在使用聚合函数max(),它将返回一组行的一列的最大值。

让我们看一些数据。我重命名了您称为“日期”的列。

create table sales (
  customerId integer not null,
  saleId integer not null,
  saledate date not null
  );


insert into sales values
(1, 10, '2013-05-13'),
(1, 11, '2013-05-14'),
(1, 12, '2013-05-14'),
(1, 13, '2013-05-17'),
(2, 20, '2013-05-11'),
(2, 21, '2013-05-16'),
(2, 31, '2013-05-17'),
(2, 32, '2013-03-01'),
(3, 33, '2013-05-14'),
(3, 35, '2013-05-14');

你说

换句话说,前两行来自同一个客户(id 19),我希望他为每个客户只获得一条记录,这将是最大日期的记录,在这种情况下,第二条记录来自此列表。

select s.customerId, max (s.saledate) 
from sales s
where s.saledate <= '2013-05-16'
group by s.customerId
order by customerId;

customerId  max
--
1           2013-05-14 
2           2013-05-16
3           2013-05-14

那个表是什么意思?这意味着客户“1”购买东西的最晚日期是 5 月 16 日或之前是 5 月 14 日;客户“2”购买东西的最晚日期是 5 月 16 日或之前的日期是 5 月 16 日。如果您在联接中使用此派生表,它将返回具有一致含义的可预测结果。

现在让我们看一个稍微不同的查询。MySQL 允许这种语法,并返回下面的结果集。

select s.customerId, s.saleId, max(s.saledate) max_sale
from sales s
where s.saledate <= '2013-05-16'
group by s.customerId
order by customerId;

customerId  saleId  max_sale
--
1           10      2013-05-14
2           20      2013-05-16
3           33      2013-05-14

ID 为“10”的销售并未发生在 5 月 14 日;它发生在 5 月 13 日。这个查询产生了错误。将此派生表与销售交易表连接起来会使错误更加复杂。

这就是 Firebird 正确引发错误的原因。解决方案是从 SELECT 子句中删除 saleId。

现在,说了这么多,您可以像这样找到自 5 月 16 日以来没有销售的客户。

select distinct customerId from sales
where customerID not in
  (select customerId
  from sales
  where saledate >= '2013-05-16')

您可以像这样获得正确的 customerId 和“正确的” saleId。(我说“正确的”saleId,因为当天可能有不止一个。我只是选择了最大值。)

select sales.customerId, sales.saledate, max(saleId)
from sales
inner join (select customerId, max(saledate) max_date
            from sales
            where saledate < '2013-05-16'
            group by customerId) max_dates
        on sales.customerId = max_dates.customerId
        and sales.saledate = max_dates.max_date
inner join (select distinct customerId 
            from sales
            where customerID not in
              (select customerId
               from sales
               where saledate >= '2013-05-16')) no_sales
        on sales.customerId = no_sales.customerId
group by sales.customerId, sales.saledate

就个人而言,我发现公用表表达式使我更容易阅读这样的 SQL 语句,而不会迷失在 SELECT 中。

with no_sales as (
  select distinct customerId 
  from sales
  where customerID not in
    (select customerId
     from sales
     where saledate >= '2013-05-16')
),
max_dates as (
  select customerId, max(saledate) max_date
  from sales
  where saledate < '2013-05-16'
  group by customerId
)
select sales.customerId, sales.saledate, max(saleId)
from sales
inner join max_dates
        on sales.customerId = max_dates.customerId
        and sales.saledate = max_dates.max_date
inner join no_sales
        on sales.customerId = no_sales.customerId
group by sales.customerId, sales.saledate
于 2013-05-16T13:59:54.297 回答
1

那么您可以使用以下查询..

编辑likeitlikeit评论后所做的更改,每个CustomerID只有一行,即使我们会遇到一种情况,即我们在特定条件下为客户提供多个销售ID -

select x.customerID, max(x.saleID), max(x.x_date) from (
select s.customerId, s.saleId, max (s.date) x_date from sales s
group by s.customerId, s.saleId
having max(s.date) <= '05-16-2013'
   and max(s.date) = ( select max(s1.date) 
                         from sales s1 
                        where s1.customeId = s.customerId))x

按 x.customerID 分组

于 2013-05-16T13:01:31.720 回答
0

您可以尝试最大化s.saleId( Max(s.saleId)) 并将其从Group By子句中删除

于 2013-05-16T12:59:06.817 回答
0

子查询应该可以完成这项工作,我现在无法对其进行测试,但看起来还可以:

SELECT s.customerId, s.saleId, subq.maxdate 
FROM sales AS s 
    INNER JOIN (SELECT customerId, MAX(date) AS maxdate
            FROM sales 
            GROUP BY customerId, saleId
            HAVING MAX(s.date) <= '05-16-2013'
        ) AS subq
    ON s.customerId = subq.customerId AND s.date = subq.maxdate
于 2013-05-16T13:02:56.393 回答