iT邦幫忙

1

關於一段百思不得其解的SQL問題

  • 分享至 

  • xImage

這是MYSQL的語法。
先來個情境吧。

A表
    download_id
    data1
    data2

B表
    id
    data1
    data2

SQL 語法

DELETE FROM `A` WHERE download_id IN (SELECT download_id FROM B WHERE data1 = 6) 

認真來這邊其實有先看出一個問題。就是B表其實是沒有 download_id 的。
就我個人的看法。理論上是會報錯才對。

但是實際情況是。
它將A表的資料全刪了。

我有試著用同樣的條件在phpmyadmin
確實會符合全刪A表。

其實這我不太理解。正常單純去執行

SELECT download_id FROM B WHERE data1 = 6

它是會報錯說找不到 download_id

但整段放進去執行。居然會IN到全部。而造成A表的資料全數刪除。

想說,有無高手可以幫我解惑這個問題到底是什麼。

補充說明:

這是一個SQL語法的討論。原則上我清楚這種寫法很危險。
這是從一個舊專案看到的語法。並不是我寫的。
只是發現到這樣有點奇怪的情況,才想拿出來討論看看。

單純討論,不是要找解決方式。

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
10
純真的人
iT邦大師 1 級 ‧ 2023-05-18 17:39:38
最佳解答

那個SQL應該判斷是A表的欄位~所以才沒有報錯~
你可以試試..

DELETE FROM `A` WHERE download_id IN (SELECT A.download_id FROM B WHERE data1 = 6) 

這樣應該也是正常執行~

所以他會全部刪除~很正常...A比對A的欄位...一定符合@@"

看更多先前的回應...收起先前的回應...

嗯,這個倒是覺得有可能是這樣。後面的download_id其實是依A表。
我試試改成 B.download_id 看還會不會全刪除好了。
試完了我再回報看看。

OK!
總算了解原理了。
確實如你所說的,IN裏面的 download_id 的確是視為A表的download_id

所以 A=A。就全刪除了。

我使用了 B.download_id 果然就報錯了。

另外我也有追加一個測試。
也就是如果我將B表也增加了一個 download_id 欄位的話。
那IN內的 download_id 就會將其視為B表。不會再用A表了。

總算是解開我的疑問了。

你給了我想要追求的答案。就給你最佳解了。

恩恩~我習慣各表欄位都會欄位前表帶表格名+欄位名~
避免前驟還要 表格.欄位 這樣可以直覺判斷那個欄位是哪個表格的

這是舊案子。沒招!
只是剛好碰到這樣的SQL寫法。感到很奇特才會想來問。

要不然其實我不會這樣幹。這算找死的行為。
我是有將這段重新寫過。

只是好奇為何這樣的寫法會變成這樣而已。

各有各工程師寫法風格吧~哈~都有難為之處~

0
GGU.IN
iT邦新手 4 級 ‧ 2023-05-18 15:04:41

用IN做查詢時因B表沒有download_id,導致子查詢回傳"NULL",故直接執行了A表的刪除,你可以嘗試使用EXISTS回傳,因為EXISTS會判斷整條指令是否準確匹配

看更多先前的回應...收起先前的回應...

目前我也在想是NULL的問題,導致WHERE條件消失。
但也覺得這樣很可怕就是了。

GGU.IN iT邦新手 4 級 ‧ 2023-05-18 15:14:27 檢舉

CSDN看到這個內容:n,exists其实是两个功能差不多的sql命令,如果查询的两个表大小相当,用in和exists差别不大。

in查询相当于多个or条件的叠加,这个相信大家都比较容易理解
exists则主要用于主表的结果集小,也就是外层循环少的情况,而in是用于子查询的结果集少的情况。
exists查询时对主表(外表)用loop逐条循环查询,每次查询都会判断exists的条件语句,当 exists里的条件语句能够返回记录行时(注:无论记录行是多少,只要能返回),条件就为真,则外循环LOOP返回当前loop到的这条记录,反之如果exists里的条 件语句不能返回记录行,则当前loop到的这条记录被丢弃,exists的条件就像一个bool条件,当能返回结果集则为true,不能返回结果集则为 false.

原文链接:https://blog.csdn.net/wh445306/article/details/107024029

GGU.IN iT邦新手 4 級 ‧ 2023-05-18 15:18:39 檢舉

爬一下文看來IN 沒有true false的概念,只要有匹配到結果及為真

其實這目前也是我納悶的點。
理論上後面因該是匹配不到資料,也不太可能為真。那就不該能IN到條件。

不過「純真的人」給了另一個思維出來。搞不好可能實際情況是他說的。

經實驗証明,並不太偏向你說的。
而是偏向「純真的人」說的情況。

我多方測試後也了解為何會這樣了。
不過還是感謝與我討論。

GGU.IN iT邦新手 4 級 ‧ 2023-05-19 09:14:08 檢舉

/images/emoticon/emoticon12.gif確實如他所說,還是很好奇它的原理

若B表查詢有資料~會刪除~
但B表無資料~不會刪除~
MSSQL為例

declare @AA table(
	idx int
)

declare @BB table(
	idc int
)

insert into @AA
values(1)
,(2)

insert into @BB
values(3)
,(4)

不會刪除A表~~

delete from @AA 
where idx in(
	select idx 
	from @BB b
	where idc = 2
)

select *
from @AA

會刪除A表~~

delete from @AA 
where idx in(
	select idx 
	from @BB b
	where idc = 3
)

select *
from @AA
wilson1966 iT邦研究生 1 級 ‧ 2023-05-23 16:47:56 檢舉

所以MS SQL 較正常, MySQL 則有些疑問。

0
wilson1966
iT邦研究生 1 級 ‧ 2023-05-22 15:25:58

要不要改用MS SQL 試看看

這是舊案子發現到的寫法。
並不是新的案子。

所以要改寫 MSSSQL 是有困難的。
雖然這有用DB庫,不過我想換成MSSQL DRIVE的話。
可能會報錯連連。

畢竟是5年多前寫的案子了。
有太多不正規的SQL寫法。

我要發表回答

立即登入回答