了解基本 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 查询的主要内容,如果未能解决你的问题,请参考以下文章