2015-12-17 83 views
0

我寫了這個查詢。但是,我想知道是否有更好的/專業的方式來重寫這個。什麼是SELECT ...,(SELECT ... FROM ...)FROM(SELECT ... FROM(SELECT ... FROM ...))`類型的構造的最佳選擇?

查找將在當年獲得獎金的員工。獲得獎金的條件是,他必須出售至少4000美元的特定類別的產品。

select yy.CurrentMonth, yy.ID, yy.Name, sum(yy.commission) as comm_total, sum(yy.bonus) as bonus_total 
from 
(select sysdate as CurrentMonth, ee.ID, ee.Name, cc.commission, (cc.commission * 25/100) as bonus 
from employee ee, 
(select e.id, pc.category_name, sum(quantity) as qty, pc.commission_rate, sum(quantity*pc.commission_rate) as commission 
from sales s, product p, product_category pc, employee e 
where to_char(sales_date, 'yyyy') = to_char(sysdate, 'yyyy') 
and s.employee_id = e.id 
and s.product_id = p.id 
and p.product_category_name = pc.category_name 
group by pc.category_name, e.id, pc.commission_rate 
order by e.id) cc 
where ee.ID = cc.id 
and cc.commission >=4000 
) yy 
group by yy.ID, yy.Name, yy.CurrentMonth 

編輯:表模式:

CREATE TABLE "XYZ"."EMPLOYEE" 
    ( "ID" NUMBER, 
    "NAME" VARCHAR2(20 BYTE), 
    "AREA_NUMBER" NUMBER, 
    "EMP_TYPE_NAME" VARCHAR2(20 BYTE) 
    ); 
-------------------------------------------------------- 
-- DDL for Table PRODUCT 
-------------------------------------------------------- 

    CREATE TABLE "XYZ"."PRODUCT" 
    ( "ID" NUMBER, 
    "NAME" VARCHAR2(20 BYTE), 
    "PRODUCT_CATEGORY_NAME" VARCHAR2(20 BYTE) 
    ) ; 
-------------------------------------------------------- 
-- DDL for Table SALES 
-------------------------------------------------------- 

    CREATE TABLE "XYZ"."SALES" 
    ( "RECEIPT_NUMBER" NUMBER, 
    "SALES_DATE" DATE, 
    "QUANTITY" NUMBER, 
    "PRODUCT_ID" NUMBER, 
    "EMPLOYEE_ID" NUMBER 
    ); 
-------------------------------------------------------- 
-- DDL for Table PRODUCT_CATEGORY 
-------------------------------------------------------- 

    CREATE TABLE "XYZ"."PRODUCT_CATEGORY" 
    ( "CATEGORY_NAME" VARCHAR2(20 BYTE), 
    "COMMISSION_RATE" FLOAT(126) 
    ) ; 
+2

1.在選擇列表中按照相同的順序編寫列。 – jarlh

+2

2.使用現代顯式的'JOIN'語法。 – jarlh

+2

3.縮進... – jarlh

回答

2

您可以使用多步熱膨脹係數,使用indenation,使用JOIN語法,避免排長隊,利用關鍵字,避免子查詢排序等:

WITH cte AS 
(
    SELECT e.id 
     ,pc.category_name 
     ,pc.commission_rate 
     ,SUM(quantity)      AS qty 
     ,SUM(quantity * pc.commission_rate) AS commission 
    FROM sales s 
    JOIN product p 
    ON s.product_id = p.id 
    JOIN product_category pc 
    ON p.product_category_name = pc.category_name 
    JOIN employee e 
    ON s.employee_id = e.id 
    WHERE TO_CHAR(sales_date, 'yyyy') = TO_CHAR(SYSDATE, 'yyyy') 
    GROUP BY e.id, pc.category_name, pc.commission_rate 
), cte2 AS 
(
    SELECT SYSDATE AS CurrentMonth 
     ,ee.ID 
     ,ee.Name 
     ,cc.commission 
     ,(cc.commission * 25/100) AS bonus 
    FROM cte cc 
    JOIN employee ee 
    ON ee.ID = cc.id 
    WHERE cc.commission >= 4000 
) 
SELECT CurrentMonth 
     ,ID 
     ,Name 
     ,SUM(commission) AS comm_total 
     ,SUM(bonus)  AS bonus_total 
FROM cte2 
GROUP BY CurrentMonth, ID, Name; 
+1

非常好,我個人討厭這樣的結構'SELECT ...,(SELECT ... FROM ...)FROM(SELECT ... FROM(SELECT ... FROM ...)' –

+0

@WernfriedDomscheit你可以儘管如此,從標量子查詢緩存中獲得好處,因此不喜歡標量子查詢(例如'select ...(從...中選擇colx ...)...作爲一般規則可能不是那麼好的事情.. 。 – Boneist

+1

@WernfriedDomscheit,什麼是'SELECT ...,(SELECT ... FROM ...)FROM(SELECT ... FROM(SELECT ... FROM ...))'類型的結構? – anonymous

2

我相信你不需要對員工表進行額外的連接 - 你只是想排除那些總和醫學委員會是< 4000,對吧?如果是這樣,你可以很容易地做到這組通過查詢使用having條款,如:

with sum_categories as (select e.id, 
           e.name, 
           pc.category_name, 
           sum(s.quantity) as qty, 
           pc.commission_rate, 
           sum(s.quantity * pc.commission_rate) as commission 
         from  sales s 
           inner join product p on (s.product_id = p.id) 
           inner join product_category pc on (p.product_category_name = pc.category_name) 
           inner join employee e on (s.employee_id = e.id) 
         where trunc(sales_date, 'yyyy') = trunc(sysdate, 'yyyy') 
         group by pc.category_name, 
           e.id, 
           e.name, 
           pc.commission_rate 
         having sum (quantity * pc.commission_rate) >= 4000) 
select sysdate currentmonth, -- should this be trunc(sysdate, 'mm')? 
     yy.id, 
     yy.name, 
     sum (yy.commission) as comm_total, 
     sum (yy.commission * 25/100) as bonus_total 
from  sum_categories yy 
group by yy.id, 
     yy.name; 

你會注意到,我改變了你的to_char(sales_date, 'yyyy') = to_char(sysdate, 'yyyy')trunc(sales_date, 'yyyy') = trunc(sysdate, 'yyyy')因爲我喜歡保持正確的數據類型之間的比較(你正在比較兩個日期,所以我想保留它們作爲日期)。

+0

什麼是SELECT ...,(SELECT ... FROM ...)FROM(SELECT ... FROM(SELECT ... FROM ...)的最佳選擇)'類型的構造? – anonymous

+0

答案是......它依賴於當你必須維護或調試sql語句時,使你的查詢可讀性非常重要。唱subquery保理(也就是with clause)可以幫助使事情可讀。其他事情如將標量子查詢更改爲連接(反之亦然)可能會影響性能。但是,它完全取決於您的數據和表結構,哪個性能最好。 – Boneist