ORA-00904:嵌套子查询中的标识符无效

时间:2015-09-16 21:54:20

标签: sql oracle

假设我们有这样的查询:

SELECT 
tt.id first_column,
tt.value second_column,
--another values
qq.code_1 third_column,
qq.code_2 column4,
qq.code_3 column5,
qq.code_4 column6,
qq.code_5 column7

FROM
test_tbl tt LEFT JOIN
(SELECT * FROM (
  SELECT id, code_value, ROW_NUMBER() OVER (ORDER BY code_value) AS RN
  FROM attributes attr WHERE attr.id = tt.id AND 
      attr.code IN ('ATTRIBUTE_CODE_1',
                    'ATTRIBUTE_CODE_2',
                    'ATTRIBUTE_CODE_3',
                    'ATTRIBUTE_CODE_4',
                    'ATTRIBUTE_CODE_5')
)
PIVOT (MAX(code_value) FOR (RN) IN (1 as code_1, 2 as code_2, 3 as code_3, 4 as code_4, 5 as code_5))) qq
ON tt.id = qq.id
-- LEFT JOINS with another tables...

问题是错误:

ORA-00904: "TT"."ID": invalid identifier

我怎样才能绕过这个障碍?

当然上面的例子很容易和虚拟,真正的查询更复杂。

此示例可在此处查看:http://sqlfiddle.com/#!4/eec83/3

3 个答案:

答案 0 :(得分:1)

只需删除有问题的条件:

WHERE attr.id = tt.id

...但为确保RN值正确,您还需要在partition by id条款中添加row_number() over

ROW_NUMBER() OVER (PARTITION BY id ORDER BY code_value) AS RN

SQLFiddle Demo

SELECT 
tt.id first_column,
tt.value second_column,
--another values
qq.code_1 third_column,
qq.code_2 column4,
qq.code_3 column5,
qq.code_4 column6,
qq.code_5 column7

FROM
test_tbl tt LEFT JOIN
(SELECT * FROM (
  SELECT id, code_value, ROW_NUMBER() OVER (partition by id ORDER BY code_value) AS RN
  FROM attributes attr WHERE
      attr.code IN ('ATTRIBUTE_CODE_1',
                    'ATTRIBUTE_CODE_2',
                    'ATTRIBUTE_CODE_3',
                    'ATTRIBUTE_CODE_4',
                    'ATTRIBUTE_CODE_5')
)
PIVOT (MAX(code_value) FOR (RN) IN (1 as code_1, 2 as code_2, 3 as code_3, 4 as code_4, 5 as code_5))) qq
ON tt.id = qq.id

答案 1 :(得分:1)

您无法在内联视图中引用其他表/视图。我找不到一个说明这一点的文档,但就是这样。这是设计,查询优化器如何处理查询。

使用这个简单的查询,实际情况更为明显:

SELECT 
  *
FROM
  test_tbl tt , 
  ( 
    SELECT ID, CODE_VALUE
    FROM attributes attr 
    WHERE attr.id = tt.id
    ) qq 

错误:

ORA-00904: "TT"."ID": invalid identifier

如果要进行连接,则应使用JOIN并将条件放在ON子句中,或将条件放在WHERE子句中以加入内联视图和表。 像这里:

SELECT 
  *
FROM
  test_tbl tt , 
  ( 
    SELECT ID, CODE_VALUE
    FROM attributes attr 
    ) qq 
WHERE attr.id = tt.id

或者查看您是否要制作CROSS APPLY。这似乎是一个加入。

另见answer,有一个很好的表达方式:

  

内联视图/派生表在查询开头创建一个临时的未命名视图,然后将其视为另一个表,直到操作完成。因为编译器在查看FROM行上的这些子查询时需要创建一个临时视图,所以这些子查询必须完全是自包含的,而子查询之外没有引用。

我相信并非总是如此,在某些情况下,oracle可以选择合并内联视图。并且可以通过使用NO_MERGE优化器提示强制合并。

SEE THIS

SEE THIS

我打算尽快添加查询计划,这可能会提供更多的想法

答案 2 :(得分:0)

您可以从内部子查询中删除该条件,因为它没有任何意义,因为您已经在其公共列id上的两个表上都留下了外部联接。

您可以在下面对查询进行更改。

SELECT 
tt.id first_column,
tt.value second_column,
qq.code_1 third_column,
qq.code_2 column4,
qq.code_3 column5,
qq.code_4 column6,
qq.code_5 column7
FROM
test_tbl tt LEFT JOIN
(SELECT * FROM (
  SELECT id, code_value, ROW_NUMBER() OVER (ORDER BY code_value) AS RN
  FROM attributes attr WHERE 
     attr.code IN ('ATTRIBUTE_CODE_1',
                'ATTRIBUTE_CODE_2',
                'ATTRIBUTE_CODE_3',
                'ATTRIBUTE_CODE_4',
                'ATTRIBUTE_CODE_5')
)
PIVOT (MAX(code_value) FOR (RN) 
IN (1 as code_1, 2 as code_2, 3 as code_3, 4 as code_4, 5 as code_5))) qq
ON tt.id = qq.id;  

这是您的Updated SQL Fiddle

愿这对你有所帮助。