结合sql中的rank和sum

时间:2017-08-31 03:14:03

标签: sql oracle

DB - Oracle。省略了所有约束。

create table customer (cid number(10), cname varchar(50));

create table exercise (eid number(10), ecode varchar(2), score number(2));

-- mapping table
create table customer_exercise (cid number(10), eid number(10), cnt number(10))  

Customer table

cid    cname
100    e1
200    e2
300    e3
400    e4

Exercise table

eid    ecode   score
1      c1       5
2      c2       10
3      c3       6
4      c4       3

Customer_Exercise

cid  eid count
100   1    2
200   2    5
100   2    3
300   4   10 

用于检索总计数的SQL -

 SELECT   c.cid
    ,e.eid
    ,COALESCE(SUM(ce.cnt), 0) AS total_cnt
FROM customer c
     CROSS JOIN exercise e
     LEFT JOIN customer_exercise ce
        ON     ce.cid = c.cid
           AND ce.eid = e.eid
WHERE c.cid IN (100, 200, 300)
      AND e.eid IN (1, 2)
GROUP BY c.cid, e.eid
ORDER by c.cid

结果 -

c.cid e.eid total_cnt
100    1         2
100    2         3
200    1         0
200    2         5
300    1         0
300    2         0

计算每个客户的排名的SQL -

select cid , RANK() OVER (ORDER BY sum(total_score) desc) as rank from 
(
SELECT   c.cid as cid
    ,e.eid
    ,COALESCE(SUM(ce.cnt), 0) AS total_cnt
    , COALESCE(SUM(ce.cnt), 0) * e.score as total_score
FROM customer c
     CROSS JOIN exercise e
     LEFT JOIN customer_exercise ce
        ON     ce.cid = c.cid
           AND ce.eid = e.eid
WHERE     c.cid IN (100, 200, 300)
     AND e.eid IN (1, 2)
GROUP BY c.cid, e.eid, e.score 
)
GROUP BY cid
ORDER BY rank

结果 -

 c.cid  rank
  200    1
  100    2
  300    3

是否可以使用一个查询而不是上面的两个查询来获取结果集?我希望将上面两个查询的结果合并为一个。预期结果发布在下面。

预期结果 -

c.cid   e.eid    total_cnt  rank
200       1      0           1  
200       2      5           1
100       1      2           2
100       2      3           2
300       1      0           3
300       2      0           3

4 个答案:

答案 0 :(得分:4)

三个表的连接使用两次 - 一次显示计数,再一次计算排名。第一个版本未聚合,而第二个版本是(并且在聚合后计算分析等级)。这是WITH子句的完美应用:在一个因子子查询(CTE,WITH子句)中连接三个表并使用它两次。

with
     j ( cid, eid, score, cnt ) as (
       select c.cid, e.eid, e.score, ce.cnt
       from   customer c cross join exercise e
              left outer join customer_exercise ce   on c.cid = ce.cid
                                                    and e.eid = ce.eid
       where  c.cid in (100, 200, 300)
         and  e.eid in (1, 2)
     )
select j.cid, j.eid, nvl(j.cnt, 0) as total_count, r.rnk
from   j left join ( select   cid, 
                              rank() over (order by sum(cnt*score) desc nulls last) as rnk
                     from     j
                     group by cid
                   ) r
                     on j.cid = r.cid
order by rnk, eid
;

答案 1 :(得分:0)

您可以使用 SUM(...)OVER(...)计算每位客户的总分,然后按此值排名。

SELECT  cid, eid, SUM(cnt) AS total_cnt, DENSE_RANK() OVER (ORDER BY cid, total_score DESC) AS rank
FROM
    (
       select c.cid, e.eid, e.score, ce.cnt, SUM(ce.cnt * ce.score) OVER (PARTITION BY c.cid) AS total_score
       from   customer c cross join exercise e
              left outer join customer_exercise ce   on c.cid = ce.cid
                                                    and e.eid = ce.eid
       where  c.cid in (100, 200, 300)
         and  e.eid in (1, 2) 
    ) data   
GROUP BY cid, eid, total_score
ORDER BY rank, eid

我创建了一个演示here

答案 2 :(得分:0)

我会用两级分析函数来做这件事:

select cid, eid, score, cnt,
       dense_rank() over (order by coalece(total_score, 0) desc) as rnk
from (select c.cid, e.eid, e.score, ce.cnt,
             sum(e.score) over (partition by c.cid) as total_score
      from customer c cross join
           exercise e left outer join
           customer_exercise ce
           on c.cid = ce.cid and e.eid = ce.eid
      where  c.cid in (100, 200, 300) and e.eid in (1, 2)
     ) ce;

答案 3 :(得分:-1)

您还可以使用$image = app('App\Helpers\ImageHelper');专门用于 MS SQL数据库查询

multiple CTE + SUM + DENSE_RANK()