[英]JOIN Alternative to SELECT Subquery
我正在尝试将SELECT子查询转换为JOIN语句,因此它适用于Netezza。 我最初是在Oracle数据库上工作,在该数据库中以下查询可以正常工作,但是Netezza不支持SELECT语句中的子查询。 我设法将SELECT子查询放入ON语句,但Netezza也不支持。
我的查询试图通过查找每日销售量和该日期的历史价格来查找单个产品销售的每日收入。
关于如何将此语句分解为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
;
将子查询移至JOIN ON语句:
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 ║
╚═══════════╩═════════╩════════╝
如果可以在FROM
子句中执行内联视图...,或者,如果您具有CREATE VIEW
DBA特权,则可以执行以下操作:
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并摆脱标量子查询。
对于通过查找每日销售数量和该日期的历史价格来查找单个产品销售的每日收入的任务,我建议采用以下方法:
在第一步中,定义(扩展)产品价格有效期。 这是通过简单的分析功能完成的(如果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
产生包含PRICE和有效FROM-有效TO日期的价格表。 请注意,两个日期都包含在内(在-1天完成),最后一个TO日期在很远的将来,这允许使用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
该查询是对产品的简单联接(如果历史表可能不完整,请使用外部联接并使用一些虚拟价格),并使用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
;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.