SQL - 如何在条件下检索聚合结果

时间:2015-01-10 11:42:55

标签: sql sql-server

例如 - 给定表players

id name date      deposit
1  tom  1.1.2014  30
2  roy  2.1.2014  40
3  tom  2.1.2014  80
4  liat 4.1.2014  105
5  tom  6.1.2014  30

检索玩家namesdate以及通过100存款的玩家的存款总额。 (date应该是玩家通过的day 100) 在示例中,结果应为:

tom  2.1.2014 110  
liat 4.1.2014 105

感谢 罗伊

4 个答案:

答案 0 :(得分:2)

您没有指定DBMS,但这是ANSI(标准)SQL:

with summed as (
  select name, 
         date, 
         sum(deposit) over (partition by name order by date) as deposit
  from players
)
select s1.*
from summed s1
where s1.total_deposit > 100
  and s1.date = (select min(date)
                 from summed s2
                 where s2.name = s1.name
                   and s2.total_deposit > 100)
order by name;

似乎(至少对Postgres而言)这更有效率(但是如此微小的数据集真的很难说):

with summed as (
  select name, 
         date, 
         sum(deposit) over (partition by name order by date) as deposit
  from players
), numbered as (
  select s1.*, 
         row_number() over (partition by name order by date) as rn
  from summed s1
  where s1.deposit >= 100
)
select name, date, deposit
from numbered
where rn = 1
order by name;

SQLFiddle示例:http://sqlfiddle.com/#!15/d4590/13

但是,通过适当的索引,Uri的解决方案可能仍然更有效。


顺便说一句:date是一个可怕的名字。因为它是一个保留字,但更重要的是它不记录列包含的内容。一个“玩过的日期”? “截止日期”? “存款日期”? “有效期至”日期?

答案 1 :(得分:1)

如果您使用的是支持累积金额的数据库,则可以从以下开始:

select p.*,
       sum(p.deposit) over (partition by p.name order by p.date) as cumedeposit,
       sum(p.deposit) over (partition by p.name) as totdeposit
from players p;

以下内容获取有关玩家何时越过100存款标记的信息:

select p.name, p.date, p.totdeposit
from (select p.*,
             sum(p.deposit) over (partition by p.name order by p.date) as cumedeposit,
             sum(p.deposit) over (partition by p.name) as totdeposit
      from players p
     ) p
where cumedeposit >= 100 and cumdeposit - deposit < 100;

如果您的数据库不支持累积和和/或窗口函数,则可以对相关子查询执行相同的操作。

答案 2 :(得分:0)

使用此技术计算SQL中的cumulative sum

SELECT p.name, p.date,p.cumsum as total_deposit FROM
(
select t1.name, t1.date, SUM(t2.deposit) as cumsum
from players t1
inner join players t2 on t1.date >= t2.date and and t1.name = t2.nam
group by t1.name, t1.date
) p
WHERE p.cumsum>100
GROUP BY p.name
HAVING  p.date=MIN(p.date)

答案 3 :(得分:0)

试试这个:

select p1.name,sum(p1.deposit) as deposit , (select p2.date from players p2 where p2.id = p1.id) 
from players p1 where p1.deposit >= 100
group by p1.id,p1.name