如何使用从一个子查询到另一个子查询的列

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.delegation 这将首先为第二个子查询生成ROW_NUMBER,然后尝试按价格过滤; OP想先按价格过滤,然后生成ROW_NUMBER @behzadomidi db<>fiddle 如果最早updated_at 的行具有delegation &lt;= price,即使存在具有state = 'yellow'delegation &gt; price 和后面的 updated_at 值。【参考方案3】:

我们需要将您的 usersprice 表重新加入您的 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 修复了这些问题,似乎可以处理一些测试数据。

以上是关于如何使用从一个子查询到另一个子查询的列的主要内容,如果未能解决你的问题,请参考以下文章

.htaccess 从一个子文件夹重定向到另一个子文件夹

将变量从一个子传递到另一个

如何将数据从子视图传递到父视图到 SwiftUI 中的另一个子视图?

如何从Oracle中的另一个子查询中选择具有最大列的行

从一个子查询更新两行

在一个子窗体中的控件上使用 AfterUpdate 事件来重新查询另一个子窗体中的控件