【问题标题】:Understanding a basic SQL query了解基本 SQL 查询
【发布时间】:2012-07-17 08:12:04
【问题描述】:

我有一个类似的查询

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

【问题讨论】:

  • “上述代码运行良好”是什么意思。 - 它会返回一些输出,但您到底想通过这个查询实现什么?您正在尝试从 customer_id 满足的行中获取 tran_number - 什么?

标签: sql oracle subquery


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    这是范围的问题。 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 参考确实解释了子查询中作用域的操作,但很难找到。这是什么it says

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

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

    【讨论】:

      【解决方案3】:

      这是 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) 
      

      【讨论】:

      • 我认为将范围规则的正确操作描述为“错误”是不正确的。更准确地说,范围允许我们在不注意的情况下引入自己的错误。
      猜你喜欢
      • 1970-01-01
      • 2013-01-27
      • 1970-01-01
      • 2014-02-10
      • 2016-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-17
      相关资源
      最近更新 更多