SQL找到连续的季度

时间:2011-08-19 03:17:27

标签: mysql sql oracle

我想给会员这个班级的费用折扣20% 谁在上一季度参加了一个班级(如果一个成员采取 连续三个季度的课程,她将在过去两个季度获得折扣)。并总结了我给出的所有折扣($)。

以下是数据库中的表格:

ENROLLMENT (class_id,member_id,cost)

CLASS (class_id,季节,年份)和属性季节可能是春季,夏季,秋季,冬季。

数据看起来像这样:

注册

Class_id  Member_id  Cost
--------  ---------  ----
3         3          20 
1         9          15 
2         9          20 
4         10         30 
3         10         10 
5         5          10 
4         9          30 
...

class_id  Season  Year 
--------  ------  ----
1         Spring  2008 
2         Fall    2008 
3         Spring  2009 
4         Winter  2008 
5         Summer  2008 
...

4 个答案:

答案 0 :(得分:0)

由于您的宿舍在几个月内完成,找到“最后两个”并不容易,所以我假设它们是在查询中指定的。

这样的事情应该有效:

SET @q0_season = 'Fall';
SET @q0_year = 2011;
SET @q1_season = 'Summer';
SET @q1_year = 2011;
SET @q2_season = 'Spring';
SET @q2_year = 2011;


SELECT DISTINCT e.class_id, e.member_id, e.cost, if (max(e1.member_id) is null, 0, 0.20) * if(max(e2.member_id) is null, 1, 2) discount
FROM enrollment e
INNER JOIN class c 
    ON c.class_id = e.class_id 
    AND c.season = @q0_season AND c.year = @q0_year
LEFT JOIN (enrollment e1 
    INNER JOIN class c1 ON c1.class_id = e1.class_id
        AND c1.season = @q1_season AND c1.year = @q1_year)
    ON e1.member_id = e.member_id
LEFT JOIN (enrollment e2
    INNER JOIN class c2 ON c2.class_id = e2.class_id
        AND c2.season = @q2_season AND c2.year = @q2_year)
    ON e2.member_id = e.member_id
GROUP BY e.class_id, e.member_id, e.cost;

答案 1 :(得分:0)

尝试这个

select member_id, cost*0.8 as cost_discount, cost
from Enrollment e inner join
(select member_id, 
    group_concat(season ORDER BY season SEPARATOR ',') as group_season, year as year1 
    from class as c inner join ENROLLMENT as e on (c.class_id=e.class_id) group by Member_id, year
    having group_season='winter,spring,summer' or group_season='spring,summer,fall'
     or LOCATE('fall',group_season) <> 0 
) as t
on t.member_id=e.member_id inner join class as c on (c.class_id=e.class_id)
where year1='2011' and locate(season, substr(group_season, 7))

不幸的是我没有在语法错误上检查这个。折扣总和:

select sum(cost - cost_discount) from (first_query);

答案 2 :(得分:0)

建议:使用calendar table

每天你都需要一行(过去和将来的日期),这应该只有几万行(以后总能增加更多行);

每行可以具有以下属性(列):

effective_date
current_quarter_season
current_quarter_year
prior_quarter_season
prior_quarter_year
next_prior_quarter_season
next_prior_quarter_year

也许你可以想出更好的名字:)

当然,它是非规范化的,但这是一个辅助的'帮助'表,因此更新异常不应成为问题。然后,您可以使用这些属性创建联接,而不是计算前一季和下一季以及它们在飞行中的年份。

这个想法是SQL是一种声明性语言,最适用于日历表等声明性解决方案。

答案 3 :(得分:0)

首先,您的数据模型让您感到困难。您需要一种简单的方法来发现连续的季度,所以,您需要一个表来保存该信息,其中一个键是一个上升的增量:您还希望计算机知道2009年春季之后是否会追随2008年冬季?

无论如何,这是我的测试数据版本。我正在使用名称来更容易地看到发生了什么:

SQL> select s.name as student
  2         , c.name as class
  3         , q.season||' '||q.year as quarter
  4         , q.q_id
  5         , c.base_cost
  6  from  enrolments e
  7          join students s
  8              on (s.s_id = e.s_id)
  9          join classes c
 10              on (c.c_id = e.c_id)
 11          join quarters q
 12              on (q.q_id = c.q_id)
 13  order by s.s_id, q.q_id
 14  /

STUDENT    CLASS                QUARTER               Q_ID  BASE_COST
---------- -------------------- --------------- ---------- ----------
Sheldon    Introduction to SQL  Spring 2008            100        100
Sheldon    Advanced SQL         Spring 2009            104        150
Howard     Introduction to SQL  Spring 2008            100        100
Howard     Information Theory   Summer 2008            101         75
Rajesh     Information Theory   Summer 2008            101         75
Leonard    Crypto Foundation    Autumn 2008            102        120
Leonard    PHP for Dummies      Winter 2008            103         90
Leonard    Advanced SQL         Spring 2009            104        150

8 rows selected.

SQL>

如您所见,我有一个表QUARTERS,其主键Q_ID以日历顺序递增1。

我将使用Oracle语法来解决这个问题,特别是LAG分析函数:

SQL> select s.name as student
  2         , c.name as class
  3         , q.season||' '||q.year as quarter
  4         , q.q_id
  5         , c.base_cost
  6         , lag (q.q_id) over (partition by s.s_id order by q.q_id) prev_q_id
  7  from  enrolments e
  8          join students s
  9              on (s.s_id = e.s_id)
 10          join classes c
 11              on (c.c_id = e.c_id)
 12          join quarters q
 13              on (q.q_id = c.q_id)
 14  order by s.s_id, q.q_id
 15  /

STUDENT    CLASS                QUARTER               Q_ID  BASE_COST  PREV_Q_ID
---------- -------------------- --------------- ---------- ---------- ----------
Sheldon    Introduction to SQL  Spring 2008            100        100
Sheldon    Advanced SQL         Spring 2009            104        150        100
Howard     Introduction to SQL  Spring 2008            100        100
Howard     Information Theory   Summer 2008            101         75        100
Rajesh     Information Theory   Summer 2008            101         75
Leonard    Crypto Foundation    Autumn 2008            102        120
Leonard    PHP for Dummies      Winter 2008            103         90        102
Leonard    Advanced SQL         Spring 2009            104        150        103

8 rows selected.

SQL>

因此,通过查看PREV_Q_ID列,我们可以看到霍华德,谢尔顿和伦纳德各自选择了不止一门课程。只有伦纳德参加了三门课程。通过比较PREV_Q_ID和Q_ID列中的值,我们可以看出霍华德的两个课程是在连续的宿舍,而谢尔顿则不是。

现在我们可以做一些数学运算:

SQL> select student
  2          , class
  3          , quarter
  4          , base_cost
  5          , discount*100 as discount_pct
  6          , base_cost - (base_cost*discount) as actual_cost
  7  from
  8          ( select student
  9                  , class
 10                  , quarter
 11                  , base_cost
 12                  , case
 13                      when prev_q_id is not null
 14                           and q_id - prev_q_id = 1
 15                      then 0.2
 16                      else 0
 17                    end       as discount
 18                 , s_id
 19                 , q_id
 20            from
 21                  (
 22                  select s.name as student
 23                         , c.name as class
 24                         , q.season||' '||q.year as quarter
 25                         , q.q_id
 26                         , c.base_cost
 27                         , lag (q.q_id) over (partition by s.s_id order by q.q_id) prev_q_id
 28                         , s.s_id
 29                  from  enrolments e
 30                          join students s
 31                              on (s.s_id = e.s_id)
 32                          join classes c
 33                              on (c.c_id = e.c_id)
 34                          join quarters q
 35                              on (q.q_id = c.q_id)
 36                  )
 37          )
 38  order by s_id, q_id
 39  /

(人工休息以避免向下滚动以查看结果)

STUDENT    CLASS                QUARTER      BASE_COST DISCOUNT_PCT ACTUAL_COST
---------- -------------------- ----------- ---------- ------------ -----------
Sheldon    Introduction to SQL  Spring 2008        100            0         100
Sheldon    Advanced SQL         Spring 2009        150            0         150
Howard     Introduction to SQL  Spring 2008        100            0         100
Howard     Information Theory   Summer 2008         75           20          60
Rajesh     Information Theory   Summer 2008         75            0          75
Leonard    Crypto Foundation    Autumn 2008        120            0         120
Leonard    PHP for Dummies      Winter 2008         90           20          72
Leonard    Advanced SQL         Spring 2009        150           20         120

8 rows selected.

SQL>

所以,霍华德和伦纳德的连续课程可以获得折扣,谢尔顿和拉吉也没有。