【问题标题】: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": 标识符无效

标签: sql oracle


【解决方案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.serialdb<>fiddle 修复了这些问题,似乎可以处理一些测试数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-16
    • 1970-01-01
    • 2017-05-29
    • 2022-10-15
    • 2020-09-10
    • 1970-01-01
    相关资源
    最近更新 更多