了解基本 SQL 查询

Posted

技术标签:

【中文标题】了解基本 SQL 查询【英文标题】:Understanding a basic SQL query 【发布时间】: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 - 什么? 【参考方案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) 

【讨论】:

我认为将范围规则的正确操作描述为“错误”是不正确的。更准确地说,范围允许我们在不注意的情况下引入自己的错误。

以上是关于了解基本 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

Mysql第三期 基本查询语句结构

SQL注入:基本查询原理

基本功:SQL 多表联合查询的几种方式

直通查询如何提高速度?

第八周access课总结

简单了解SQL(结构化查询语言)