我需要解释为什么在子查询中忽略 MIN/MAX 函数。我在文档中没有找到任何有关见面行为的内容。
例如
有2张桌子
CREATE TABLE A(COL1 NUMBER);
CREATE TABLE B(COL1 NUMBER);
Run Code Online (Sandbox Code Playgroud)
通过以下 PL/SQL 块填充数据
SET TIMING ON
DECLARE
INSERT_STATEMENT VARCHAR2(200);
BEGIN
FOR I IN 1..100
LOOP
INSERT_STATEMENT := 'INSERT INTO A(COL1) VALUES(round(DBMS_RANDOM.VALUE(1,3)))';
EXECUTE IMMEDIATE INSERT_STATEMENT;
INSERT_STATEMENT := 'INSERT INTO B(COL1) VALUES(round(DBMS_RANDOM.VALUE(1,2)))';
EXECUTE IMMEDIATE INSERT_STATEMENT;
END LOOP;
commit;
END;
/
Run Code Online (Sandbox Code Playgroud)
表值的分布
SELECT COL1,COUNT(COL1) COUNT# FROM A GROUP BY COL1;
SELECT COL1,COUNT(COL1) COUNT# FROM B GROUP BY COL1;
COL1 COUNT#
---------- ----------
1 26
2 53
3 21
SQL>
COL1 COUNT#
---------- ----------
1 50
2 50
Run Code Online (Sandbox Code Playgroud)
“问题”查询是
SQL> SELECT COUNT(*) FROM A WHERE A.COL1=(SELECT MIN(B.COL1) FROM B WHERE A.COL1=B.COL1);
COUNT(*)
----------
79
SQL> SELECT COUNT(*) FROM A WHERE A.COL1=(SELECT MAX(B.COL1) FROM B WHERE A.COL1=B.COL1);
COUNT(*)
----------
79
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 67 | 2546 | 5 (20)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | HASH GROUP BY | | 67 | 2546 | 5 (20)| 00:00:01 |
|* 3 | HASH JOIN SEMI | | 67 | 2546 | 4 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL| A | 100 | 2500 | 2 (0)| 00:00:01 |
| 5 | TABLE ACCESS FULL| B | 100 | 1300 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("A"."COL1"=MIN("A"."COL1"))
3 - access("A"."COL1"="B"."COL1")
Run Code Online (Sandbox Code Playgroud)
两个查询都从表 A 中返回 79 行,其中表 A 的值存在于表 B 中。
我有点困惑,因为我预计上面的 MIN()/MAX() 函数查询应该分别返回 26 和 53 行。但看起来 MIN/MAX 函数在此类查询中被忽略。
预期结果的工作示例
SQL> SELECT COUNT(*) FROM A A2 WHERE A2.COL1=(SELECT MIN(B.COL1) FROM A,B WHERE A.COL1=B.COL1);
COUNT(*)
----------
26
SQL> SELECT COUNT(*) FROM A A2 WHERE A2.COL1=(SELECT MAX(B.COL1) FROM A,B WHERE A.COL1=B.COL1);
COUNT(*)
----------
53
Run Code Online (Sandbox Code Playgroud)
我想知道为什么在子查询中忽略 MIN/MAX 函数
SQL> SELECT COUNT(*) FROM A WHERE A.COL1=(SELECT MIN(B.COL1) FROM B WHERE A.COL1=B.COL1);
COUNT(*)
----------
79
SQL> SELECT COUNT(*) FROM A WHERE A.COL1=(SELECT MAX(B.COL1) FROM B WHERE A.COL1=B.COL1);
COUNT(*)
----------
79
Run Code Online (Sandbox Code Playgroud)
你的子查询
(SELECT MAX(B.COL1) FROM B WHERE A.COL1=B.COL1)
Run Code Online (Sandbox Code Playgroud)
与 A 相关,因此对于 的每个值A.COL1
,如果 B 中存在具有相同COL1
值的任何行(对于 1 和 2 是这样,但对于 3 则不然),那么由于A.COL1=B.COL1
,MAX(B.COL1)
也必须等于MAX(A.COL1)
。您可以在谓词信息中看到它已转换为等效内容:
1 - filter("A"."COL1"=MIN("A"."COL1"))
3 - access("A"."COL1"="B"."COL1")
Run Code Online (Sandbox Code Playgroud)
又因为相关性,A.COL1 = MIN(A.COL1)
真的只是A.COL1 = A.COL1
。
另一种看待它的方式是,当 B 中有一行时,您实际上将子查询结果替换为:
WHERE A.COL1 = A.COL1
Run Code Online (Sandbox Code Playgroud)
对于值 1 和 2 始终为 true COL1
,对于 3 始终为 false;并且 B 中没有行,那么对于那些它被有效替换为的行:
WHERE A.COl1 = null
Run Code Online (Sandbox Code Playgroud)
这从来都不是真的。
删除这种相关性,它将执行您所期望的操作 - 如db<fiddle所示,具有不同的随机数据:
SELECT COUNT(*) FROM A WHERE A.COL1=(SELECT MIN(B.COL1) FROM B WHERE A.COL1=B.COL1);
Run Code Online (Sandbox Code Playgroud)
数数(*) |
---|
76 |
SELECT COUNT(*) FROM A WHERE A.COL1=(SELECT MAX(B.COL1) FROM B WHERE A.COL1=B.COL1);
Run Code Online (Sandbox Code Playgroud)
数数(*) |
---|
76 |
SELECT COUNT(*) FROM A WHERE A.COL1=(SELECT MIN(B.COL1) FROM B);
Run Code Online (Sandbox Code Playgroud)
数数(*) |
---|
24 |
SELECT COUNT(*) FROM A WHERE A.COL1=(SELECT MAX(B.COL1) FROM B);
Run Code Online (Sandbox Code Playgroud)
数数(*) |
---|
52 |
归档时间: |
|
查看次数: |
92 次 |
最近记录: |