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

Edit: Таблица схемы:

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 from ...) ... from ...' как правило, возможно, не так уж хорошо. – Boneist

+1

@WernfriedDomscheit, что является лучшей альтернативой 'SELECT ..., (SELECT ... FROM ...) FROM (SELECT ... FROM (SELECT ... FROM ...))' типы конструкций? – anonymous

2

Я считаю, что вам не нужно дополнительное соединение с таблицей сотрудников - вы просто хотите исключить строки, в которых сумма med комиссия < 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. пей-подзапрос факторинга (иначе говоря, с предложением) может помочь сделать чтение понятным. Другие вещи, такие как изменение скалярных подзапросов в объединениях (и наоборот), могут влиять на производительность. Однако это полностью зависит от ваших данных и табличных структур, которые будут работать лучше всего. – Boneist