2

我有一个像这样的查询

SELECT tran_number
  FROM table_a WHERE customer_id IN
          (SELECT customer_id 
             FROM table_b
            WHERE customer_key = 89564
                  AND (   other_phn_area_code
                       || other_phnum_pfx_num
                       || other_phnum_sfx_num IN
                          (123456789)))
       AND phn_area_code || phnum_pfx_num || phnum_sfx_num IN (123456789)

上面的代码工作正常。问题在于内部查询(下面单独复制内部查询)......

(SELECT customer_id 
                 FROM table_b
                WHERE customer_key = 89564
                      AND (   other_phn_area_code
                           || other_phnum_pfx_num
                           || other_phnum_sfx_num IN
                              (123456789)))

当我执行此查询时,我收到错误为customer_id: invalid identifier. 实际上,table_b没有任何名为customer_id. 如果是这样,那么当我将它用作上面的内部查询时,它是如何工作的,没有任何问题。

请帮助我理解这一点。

数据库详细信息如下

Oracle 11G Enterprise edition 11.2.0.2.0
PL/SQL Release 11.2.0.2.0
4

3 回答 3

7

如果该where内部选择的条件有结果,则将选择customer_id来自的列table_a。如果不是,则不会被选中。外部选择检查in条件。这就像说:“仅当内部选择返回 true 时才返回某些内容。”

于 2012-07-17T08:16:21.713 回答
3

这是一个范围问题。Oracle 从最里面的子查询开始验证标识符并向外工作。如果我们将表别名添加到您的原始查询中,事情可能会变得更加清晰:

SELECT t1.tran_number 
  FROM table_a t1
  WHERE t1.customer_id IN 
          (SELECT t1.customer_id  
             FROM table_b t2 
            WHERE t2.customer_key = 89564 
                  AND (   t2.other_phn_area_code 
                       || t2.other_phnum_pfx_num 
                       || t2.other_phnum_sfx_num IN 
                          (123456789))) 
       AND t1.phn_area_code || t1.phnum_pfx_num || t1.phnum_sfx_num IN (123456789) 

实际上,外部查询使用子查询作为 EXISTS 的测试,即只检查给定的 CUSTOMER_KEY 值和其他列是否存在。如果这不是您想要的,那么您应该更改子查询中的列名。(这是一个不错的选择:您可能会从主查询中得到令人费解的结果,这就是为什么您要单独调查子查询的原因)。

在这些场景中使用别名总是好的做法。如果您像这样为子查询起别名:

....
  WHERE t1.customer_id IN 
          (SELECT t2.customer_id  
             FROM table_b t2 
            WHERE t2.customer_key = 89564 
....

错误会立即显现出来。


SQL Reference 确实解释了子查询中作用域的操作,但很难找到。它说的是这样的:

“Oracle 通过查看子查询中命名的表,然后查看父语句中命名的表来解析子查询中的不合格列”

您可以在 PL/SQL 文档中找到更清晰的范围说明;SQL 子查询以同样的方式工作。 了解更多

于 2012-07-17T08:20:08.747 回答
0

那是 IN 的一个已知错误。如果你使用表别名,你会得到错误

SELECT tran_number 
  FROM table_a WHERE customer_id IN 
          (SELECT b.customer_id  
             FROM table_b b
            WHERE customer_key = 89564 
                  AND (   other_phn_area_code 
                       || other_phnum_pfx_num 
                       || other_phnum_sfx_num IN 
                          (123456789))) 
       AND phn_area_code || phnum_pfx_num || phnum_sfx_num IN (123456789) 

也使用 EXISTS 来避免这种类型的静默行为

SELECT tran_number 
  FROM table_a as t1 WHERE EXISTS  
          (SELECT *
             FROM table_b as b
            WHERE customer_key = 89564 
                  AND (   other_phn_area_code 
                       || other_phnum_pfx_num 
                       || other_phnum_sfx_num IN 
                          (123456789))
        AND b.customer_id  =t1.customer_id) 
       AND phn_area_code || phnum_pfx_num || phnum_sfx_num IN (123456789) 
于 2012-07-17T08:18:18.503 回答