了解基本的SQL查询

时间:2012-07-17 08:12:04

标签: sql oracle subquery

我有一个像

这样的查询
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

3 个答案:

答案 0 :(得分:7)

如果该内部选择的where条件具有结果,则将选择customer_id中的table_a列。 如果没有,则不会被选中。外部选择检查具有in条件的那个。这就像说:“只有在内部选择返回true时才返回一些东西。”

答案 1 :(得分: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确实解释了子查询中作用域的操作,但很难找到。 it says是什么:

  

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

您可以在PL / SQL文档中找到更明确的范围解释; SQL子查询以相同的方式工作。 Find out more

答案 2 :(得分: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)