我有以下选择,其目标是选择自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子句中)。
我正在使用firebird 1.5
我该怎么做?
答案 0 :(得分:8)
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
那张桌子是什么意思?这意味着5月16日或之前客户“1”购买东西的最新日期是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
5月14日没有发生ID为“10”的销售;它发生在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,因为当天可能会有不止一个。我只选择了最大值。)
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
答案 1 :(得分:1)
然后您可以使用以下查询..
EDIT 在每个CustomerID仅对一行进行评论后进行更改,即使我们有一个案例,我们为具有特定条件的客户提供多个saleID -
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
答案 2 :(得分:0)
您可以尝试对s.saleId
Max(s.saleId)
进行最大化并将其从Group By
子句中删除
答案 3 :(得分: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