問題描述
有開發問我這樣一個問題:
mysql> select * from aaa;
+----+---------------------+----------+---------------------+
| id | dt | name | dtt |
+----+---------------------+----------+---------------------+
| 1 | 2019-01-14 18:15:39 | aaaaaaaa | 2019-01-30 17:14:08 |
+----+---------------------+----------+---------------------+
1 row in set (0.00 sec)
mysql> select * from bbb;
+----+---------------------+----------+
| id | dt | name |
+----+---------------------+----------+
| 1 | 2019-01-14 18:19:19 | aaaaaaaa |
| 2 | 2019-01-14 18:20:49 | aaaaaaaa |
+----+---------------------+----------+
2 rows in set (0.00 sec)
mysql> select * from aaa where id in (select id from bbb where dtt<now());
+----+---------------------+----------+---------------------+
| id | dt | name | dtt |
+----+---------------------+----------+---------------------+
| 1 | 2019-01-14 18:15:39 | aaaaaaaa | 2019-01-30 17:14:08 |
+----+---------------------+----------+---------------------+
1 row in set (0.00 sec)
上面内容裡dtt這個字段在bbb表中并不存在,但是在外表中存在,但是為什麼不報錯反而查出來結果了呢?
原因
我請PostgreSQL的同僚也做了同樣的操作,也是不報錯的;
這個在SQLServer和Oracle裡面同樣成立,why?
一般規則是,語句中的列名由FROM子句中引用的表隐式地限定在同一級别。如果子查詢的FROM子句中引用的表中不存在列,則由外部查詢的FROM子句中引用的表隐式地限定列。
即:在塊結構語言計算子查詢時,它開始在本地查找以解析列名。如果失敗,則轉到外部範圍,直到找到具有該名稱的列或失敗為止。
風險
如果有開發這樣執行delete語句,可能會導緻全表被誤删!
mysql> delete from aaa where id in (select id from bbb where dtt<now());
正确又安全的寫法
帶上表名
mysql> select aaa.* from aaa where aaa.id in (select bbb.id from bbb where bbb.dtt<now());
mysql> ERROR 1054 (42S22): Unknown column 'bbb.dtt' in 'where clause'