2016-01-27 4 views
0

Я пытаюсь преобразовать подзапрос SELECT в оператор JOIN, поэтому он работает на Netezza. Я изначально работал над базой данных Oracle, где следующий запрос работал нормально, но Netezza не поддерживает подзапросы в операторах SELECT. Мне удалось получить подзапрос SELECT в оператор ON, но Netezza также не поддерживает это.JOIN Альтернатива SELECT подзапросам

Мой запрос пытается найти ежедневный доход от продаж отдельных продуктов, просматривая ежедневное количество проданных и историческую цену за эту дату.

Любые предложения о том, как разложить это утверждение на что-то, что примет Netezza? Мне также интересно узнать, может ли какая-либо реструктуризация моего запроса повысить эффективность.

Мой оригинальный Oracle SQL-запрос:

Select 
    SALES.DATE, 
    SALES.PRODUCT, 
    SALES.QUANTITY, 
    (
     Select PRICE 
     from 
     (
      Select PRODUCT_ID, PRICE, max(EFF_DATE) as EFF_DATE 
      from HIST_PRICING 
      Where 
       PRODUCT_ID = SALES.PRODUCT and 
       SALES.DATE > EFF_DATE 
      GROUP BY 
       PRODUCT_ID, PRICE 
     ) 
    ) as PRICE, 
    (SALES.QUANTITY * PRICE) as REVENUE 
FROM SALES_RECORDS SALES 
; 

Переехал подзапрос ВСТУПИТЬ НА высказыванием:

SELECT 
    SALES.DATE, 
    SALES.PRODUCT, 
    SALES.QUANTITY, 
    H.PRICE, 
    (SALES.QUANTITY * H.PRICE) as REVENUE 
FROM SALES_RECORDS SALES 
LEFT JOIN HIST_PRICING H ON 
    SALES.PRODUCT = H.PRODUCT and 
    SALES.DATE = 
     (
      Select MAX(EFF_DATE) AS MOST_RECENT 
      FROM HIST_PRICING 
      WHERE SALES.PRODUCT = HIST_PRICING.PRODUCT 
       AND EFF_DATE <= SALES.DATE 
      GROUP BY SALES.PRODUCT 
     ) 

Для справки, здесь приведен упрощенный пример того, что выглядит мои данные таблицы как.

╔═════════════════════════════════════╗ 
║   SALES_RECORDS    ║ 
╠═══════════╦═════════╦═══════════════╣ 
║ DATE ║ PRODUCT ║ QUANTITY_SOLD ║ 
╠═══════════╬═════════╬═══════════════╣ 
║ 1/1/2015 ║ SHOES ║   500 ║ 
║ 2/5/2015 ║ SHOES ║   1200 ║ 
║ 3/7/2015 ║ TOYS ║   600 ║ 
║ 3/9/2015 ║ SHOES ║   100 ║ 
║ 5/10/2015 ║ HATS ║   400 ║ 
╚═══════════╩═════════╩═══════════════╝ 
╔══════════════════════════════╗ 
║   HIST_PRICING  ║ 
╠═══════════╦═════════╦════════╣ 
║ EFF_DATE ║ PRODUCT ║ PRICE ║ 
╠═══════════╬═════════╬════════╣ 
║ 1/1/2015 ║ SHOES ║ $50 ║ 
║ 1/1/2015 ║ TOYS ║ $10 ║ 
║ 1/1/2015 ║ HATS ║ $20 ║ 
║ 2/15/2015 ║ SHOES ║ $45 ║ 
║ 2/15/2015 ║ HATS ║ $15 ║ 
║ 3/1/2015 ║ HATS ║ $20 ║ 
║ 5/1/2015 ║ TOYS ║ $15 ║ 
║ 8/1/2015 ║ SHOES ║ $55 ║ 
╚═══════════╩═════════╩════════╝ 
+0

Я не уверен, что вам нужно использовать 'LEFT JOIN'. У вас все ваши продукты существуют на столе 'HIST_PRICING'? Кроме того, вам не нужно группироваться в вашем подзапросе. –

ответ

0

Если вы можете сделать вложенное в предложении FROM ... или, если у вас есть привилегии DBA для CREATE VIEW, то вы можете сделать это:

Select 
    SALES."DATE", 
    SALES.PRODUCT, 
    SALES.QUANTITY, 
    PRICES.PRICE, 
    (SALES.QUANTITY * PRICES.PRICE) as REVENUE 
FROM SALES_RECORDS SALES LEFT JOIN 
     (
      Select PRODUCT_ID, PRICE, max(EFF_DATE) as EFF_DATE 
      from HIST_PRICING 
      GROUP BY 
       PRODUCT_ID, PRICE 
     ) PRICES ON PRICES.PRODUCT_ID = SALES.PRODUCT AND PRICES.EFF_DATE <= SALES."DATE" 
; 

В противном случае, вы можете сделать это :

Select 
    SALES."DATE", 
    SALES.PRODUCT, 
    SALES.QUANTITY, 
    PRICES.PRICE, 
    (SALES.QUANTITY * PRICES.PRICE) as REVENUE 
FROM SALES_RECORDS SALES LEFT JOIN HIST_PRICING PRICES ON PRICES.PRODUCT_ID = SALES.PRODUCT AND PRICES.EFF_DATE <= SALES."DATE" 
WHERE NOT EXISTS (SELECT 'later price for product prior to sales date' 
        FROM hist_pricing p2 
        WHERE p2.product_id = prices.product_id 
        AND p2.eff_date <= sales."DATE" 
        -- NOTE: too simple - assumes you never have two prices for the same product on the same date. 
        -- If that can happen, you need to adjust the logic below to include a tie-breaker. 
        AND p2.eff_date > prices.eff_date) 
;     

Oracle имеет все виды способов улучшить на обоих из них (например, MAX() KEEP). Но это два довольно ванильных SQL-метода для повторного выражения исходного SQL и избавления от скалярного подзапроса.

0

Для задачи , чтобы найти ежедневный доход индивидуальных продаж продукции путем поиска суточного количества проданных товаров и историческая цены за эту дату я sugest этого подхода:

На первом этапе определяет (продлить) интервал действия цены продукта. Это делается с помощью простой аналитической функции (альтернатива самосоединению, если не поддерживается в Netezza).

select PRODUCT_ID, EFF_DATE eff_date_from, 
nvl(lead(EFF_DATE-1) over (partition by product_id order by EFF_DATE),to_date('1/1/2100','mm/dd/yyyy')) eff_date_to, 
PRICE from HIST_PRICING order by PRODUCT_ID, EFF_DATE 

Дает ценовой стол с ЦЕНАМИ и действительными ОТ - действительными датами ТО. Обратите внимание, что обе даты являются включительно (выполняется с -1 днем), а последняя дата ТО - в далеком будущем, которая предусматривает простой фильтр с использованием BETWEEN.

Осторожно - это работает только для DATE (без компонента времени). Если столбец достоверности также содержит время, вы вычитаете только наименьшую единицу, например, 1 секунду.

PRODUCT_ID EFF_DATE_FROM  EFF_DATE_TO    PRICE 
---------- ------------------- ------------------- ---------- 
HATS  01.01.2015 00:00:00 14.02.2015 00:00:00   20 
HATS  15.02.2015 00:00:00 28.02.2015 00:00:00   15 
HATS  01.03.2015 00:00:00 01.01.2100 00:00:00   20 
SHOES  01.01.2015 00:00:00 14.02.2015 00:00:00   50 
SHOES  15.02.2015 00:00:00 31.07.2015 00:00:00   45 
SHOES  01.08.2015 00:00:00 01.01.2100 00:00:00   55 
TOYS  01.01.2015 00:00:00 30.04.2015 00:00:00   10 
TOYS  01.05.2015 00:00:00 01.01.2100 00:00:00   15 

Запрос представляет собой простое соединение (использование внешнего соединение с некоторой фиктивной ценой, если таблица истории может быть неполной) на продукте и сдерживающий theh цен валидности с sales_date.

Select 
    SALES."DATE", 
    SALES.PRODUCT_ID, 
    SALES.QUANTITY, 
    (SALES.QUANTITY * PRICE) as REVENUE, 
    PRICE 
from SALES_RECORDS SALES 
join 
( 
select PRODUCT_ID, EFF_DATE eff_date_from, 
nvl(lead(EFF_DATE-1) over (partition by product_id order by EFF_DATE),to_date('1/1/2100','mm/dd/yyyy')) eff_date_to, 
PRICE from HIST_PRICING order by PRODUCT_ID, EFF_DATE 
) DAILY_PRICE 
on SALES.PRODUCT_ID = DAILY_PRICE.PRODUCT_ID and 
SALES."DATE" BETWEEN DAILY_PRICE.eff_date_from and DAILY_PRICE.eff_date_to 
; 
Смежные вопросы