2011-08-19 6 views
1

회원이 지난 분기에 수업을 들었던 회원에게 해당 클래스의 비용을 20 % 할인 해드립니다. (회원이 3 분기 연속으로 클래스를 수강하면 그녀의 마지막 2 분기에 할인을받습니다). 그리고 나는 모든 할인 ($)을 요약했다.연속적인 분기 찾기

여기 데이터베이스의 테이블입니다 :

등록 (CLASS_ID, MEMBER_ID, 비용)

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 
... 
+0

[oracle] 및 [mysql]에 대한 태그가 있습니다. 데이터베이스 둘 다 또는 둘 다에 대한 솔루션을 원하십니까? ORCL 회사가 현재 MySQL 제품을 소유하고 있기 때문에 [oracle]을 포함하고 있습니까? – APC

답변

0

우선, 귀하의 데이터 모델은 당신을 힘들게 만들고 있습니다. 연속적인 분기를 쉽게 찾을 수있는 방법이 필요합니다. 따라서 상승 추세 인 키를 사용하여 해당 정보를 보관할 테이블이 필요합니다. 2008 년 봄 2009이 봄 2009 이후인지 컴퓨터가 알 수 있다고 생각하십니까?

어쨌든 여기 테스트 데이터가 있습니다.나는 쉽게 무슨 일이 일어나고 있는지 볼 수 있도록 이름을 사용하고 있습니다 : 당신이 볼 수 있듯이

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> 

, 나는 누구의 기본 키 Q_ID 증가 하나 역법 위해 테이블 ​​숙소를 가지고있다. 나는이 문제를 해결하기 위해 오라클 구문을 사용하는거야

, 특히 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 열에서 보면 우리가 하워드, 셀던과 레너드는 각각 촬영 한 것을 볼 수 있습니다 더 한 코스보다. Leonard만이 세 가지 코스를 택했습니다. PREV_Q_ID와 Q_ID 열의 값을 비교하면 Howard의 두 코스가 보존적인 구역에 있지만 Sheldon 's는 그렇지 않은 것을 알 수 있습니다.

이제 우리는 약간의 수학을 수행 할 수 있습니다

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> 

그래서, 하워드와 레너드는 자신의 연속에 대한 할인을받을 수업은 아니고 쉘든과 라즈는 그렇지 않아.

0

당신의 숙소가 달에서 수행되는 것처럼,을 찾을 쉬운 트릭이 없다 'last two', 그래서 나는 그것들이 질의에 지정되어 있다고 가정 할 것이다. 이 같은

뭔가 작업을해야합니다 :

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; 
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); 
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은 달력 테이블과 같은 선언적 솔루션에서 가장 잘 작동하는 선언적 언어입니다.