2015-12-17 627 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