如何使用从一个子查询到另一个子查询的列
Posted
技术标签:
【中文标题】如何使用从一个子查询到另一个子查询的列【英文标题】:how use column from one subquery to anoter subquery 【发布时间】:2019-10-16 08:04:57 【问题描述】:我有两个子查询。我想将 p.price 从第一个子查询放入第二个子查询(放置 XXX)。但得到错误 => ORA-00904: "P"."PRICE": invalid identifier
select
p.product_id,
p.price,
l.delegation,
l.state
from users
inner join (
select
start_date,
price,
product_id,
row_number() over (partition by serial order by start_date desc ) as rn
from prices
) p on users.serial = p.serial
inner join (
select
sso_id ,
delegation,
state,
updated_at,
row_number() over (partition by state order by updated_at asc) as tl
from payments
where state = 'green' or (state = 'yellow' and delegation > XXX)
) l on users.sso_id= l.sso_id
where
p.rn = 1
and l.tl = 1
【问题讨论】:
如果您能以表格文本的形式提供示例数据和预期结果,我会很高兴。 它给出了不同的错误。 [错误] 执行 (14: 29): ORA-00904: "P"."SERIAL": 标识符无效 【参考方案1】:加入PAYMENTS
表并过滤行以排除无效的state
/delegation
行,然后生成ROW_NUMBER
并过滤以查找每个分区的第一行:
Oracle 设置:
CREATE TABLE users ( serial, sso_id ) AS
SELECT 1, 1 FROM DUAL UNION ALL
SELECT 2, 2 FROM DUAL UNION ALL
SELECT 3, 3 FROM DUAL;
CREATE TABLE prices ( serial, start_date, price, product_id ) AS
SELECT 1, DATE '2019-01-01', 20, 1 FROM DUAL UNION ALL
SELECT 1, DATE '2019-02-01', 30, 2 FROM DUAL UNION ALL
SELECT 1, DATE '2019-03-01', 25, 3 FROM DUAL UNION ALL
SELECT 2, DATE '2019-01-01', 20, 1 FROM DUAL UNION ALL
SELECT 2, DATE '2019-02-01', 25, 2 FROM DUAL UNION ALL
SELECT 2, DATE '2019-03-01', 30, 3 FROM DUAL UNION ALL
SELECT 3, DATE '2019-01-01', 40, 3 FROM DUAL;
CREATE TABLE payments ( sso_id, delegation, state, updated_at ) AS
SELECT 1, 20, 'green', DATE '2019-01-01' FROM DUAL UNION ALL
SELECT 1, 30, 'green', DATE '2019-02-01' FROM DUAL UNION ALL
SELECT 1, 27, 'green', DATE '2019-03-01' FROM DUAL UNION ALL
SELECT 1, 22, 'green', DATE '2019-04-01' FROM DUAL UNION ALL
SELECT 1, 26, 'yellow', DATE '2019-05-01' FROM DUAL UNION ALL
SELECT 2, 31, 'yellow', DATE '2019-01-01' FROM DUAL UNION ALL
SELECT 2, 31, 'green', DATE '2019-02-01' FROM DUAL UNION ALL
SELECT 3, 30, 'green', DATE '2019-01-01' FROM DUAL UNION ALL
SELECT 3, 30, 'yellow', DATE '2019-01-01' FROM DUAL UNION ALL
SELECT 3, 50, 'yellow', DATE '2019-02-01' FROM DUAL;
查询:
SELECT product_id,
price,
delegation,
state
FROM (
select p.product_id,
p.price,
l.delegation,
l.state,
row_number() over ( partition by l.sso_id, l.state order by l.updated_at asc) as tl
from users
inner join (
select serial,
start_date,
price,
product_id,
row_number() over (partition by serial order by start_date desc ) as rn
from prices
) p
on ( users.serial = p.serial AND p.rn = 1 )
inner join payments l
on ( users.sso_id = l.sso_id AND ( l.state = 'green' or (l.state = 'yellow' and l.delegation > p.price ) ) )
)
where tl = 1
输出:
PRODUCT_ID |价格 |代表团 |状态 ---------: | ----: | ---------: | :----- 3 | 25 | 20 |绿色 3 | 25 | 26 |黄色的 3 | 30 | 31 |绿色 3 | 30 | 31 |黄色的 3 | 40 | 30 |绿色 3 | 40 | 50 |黄色的
db小提琴here
【讨论】:
【参考方案2】:在 WHERE
主子句中使用它
select
p.product_id,
p.price,
l.delegation,
l.state
from users
inner join (
select
start_date,
price,
product_id,
row_number() over (partition by serial order by start_date desc ) as rn
from prices
) p on users.serial = p.serial
inner join (
select
sso_id ,
delegation,
state,
updated_at,
row_number() over (partition by state order by updated_at asc) as tl
from payments
where state = 'green' or state = 'yellow'
) l on users.sso_id= l.sso_id
where
p.rn = 1
and l.tl = 1
-- add following condition
and l.delegation > p.price
【讨论】:
解决了!不需要 CASE ,只是我在没有 CASE 语句的主要 WHERE 子句中使用 'l.delegationROW_NUMBER
,然后尝试按价格过滤; OP想先按价格过滤,然后生成ROW_NUMBER
。
@behzadomidi db<>fiddle 如果最早updated_at
的行具有delegation <= price
,即使存在具有state = 'yellow'
和delegation > price
和后面的 updated_at
值。【参考方案3】:
我们需要将您的 users
和 price
表重新加入您的 payment
以匹配 p.price
SELECT p.product_id,
p.price,
l.delegation,
l.state
FROM users
INNER JOIN
(SELECT start_date,
price,
product_id,
ROW_NUMBER() OVER (PARTITION BY serial ORDER BY start_date DESC) AS rn
FROM prices) p ON users.serial = p.serial
INNER JOIN
(SELECT y.sso_id,
y.delegation,
y.state,
y.updated_at,
ROW_NUMBER () OVER (PARTITION BY y.state ORDER BY y.updated_at ASC) AS tl
FROM payments y
INNER JOIN users u ON u.sso_id = y.sso_id
INNER JOIN prices p ON p.serial = y.serial
WHERE tl.state = 'green' OR (tl.state = 'yellow' AND tl.delegation > p.price)) l ON users.sso_id = l.sso_id
WHERE
AND p.rn = 1 AND l.tl = 1
【讨论】:
这将首先为第二个子查询生成ROW_NUMBER
,然后尝试按状态和价格进行过滤; OP 希望先按状态和价格进行过滤,然后生成 ROW_NUMBER
。
有几个问题,因为第一个子查询缺少过滤的 serial
值,并且从 OP 的查询中不清楚 payments
表有一个 serial
列加入但是您可以在第二个子查询中使用p.serial = u.serial
。 db<>fiddle 修复了这些问题,似乎可以处理一些测试数据。以上是关于如何使用从一个子查询到另一个子查询的列的主要内容,如果未能解决你的问题,请参考以下文章