這個聲明具體是做什麼的?
該聲明
SELECT password FROM users WHERE username='' UNION SELECT 'test' FROM users
返回
password -------- test
和聲明
SELECT username, password FROM users WHERE username='' UNION SELECT 'test', 'test' FROM users
返回
username password -------- -------- test test
這裡到底發生了什麼?
因為如果您省略該
WHERE
子句,則第一個SELECT
返回所有使用者行並UNION SELECT
添加到該行test test
:username password -------- -------- johnny pw123 wiener peter test test
我知道添加
WHERE username=''
子句不會返回任何行,因此UNION SELECT
添加到任何包含test test
.但是當您只有語句
SELECT 'test, 'test' FROM users
時,它不會返回一個這樣的行,而是為每個使用者返回一行。所以多行。此語句的輸出中的行數與 users 表中的使用者數一樣多:username password -------- -------- test test <- one for johnny test test <- one for wiener
所以我試圖調和這些行為。
SELECT
上面通常會為每個使用者返回一行,但是當它添加UNION SELECT
到 first 返回的SELECT
行時,它只返回一行,而不是每個使用者一個。第一個SELECT
不返回任何內容,除非該WHERE
子句被省略,在這種情況下它返回所有使用者行。作為這個長問題的
UNION SELECT
附加內容test test
,例如username password -------- -------- johnny pw123 wiener peter
所以很自然,它們屬於“使用者名”和“密碼”列。但是,當您有
WHERE
使第一個SELECT
不返回任何內容的子句時,整個語句如何返回password username -------- -------- test test
並不是
Expr1000 Expr1000 -------- -------- test test
是因為說
SELECT
返回“無”是不准確的,而是返回“在’使用者名’和’密碼’的列下沒有行”,這意味著它為UNION SELECT
這些列建立,而不管第一SELECT
列下是否有任何行他們?我是否通過蘇格拉底的方法回答了我自己的問題?還是我的想法不對?如果我自己回答了,我很抱歉浪費你五分鐘的時間閱讀 400 字。
請注意,您應該始終將您使用的數據庫系統版本作為問題中的標籤之一,因為這通常是相關的。
我懷疑您在特定情況下遇到的問題(假設您的範例帶有測試數據)是MySQL中的
UNION
運算符發生的重複數據刪除:預設情況下,從 UNION 結果中刪除重複的行。可選的 DISTINCT 關鍵字具有相同的效果,但使其顯式。使用可選的 ALL 關鍵字,不會刪除重複行,結果包括所有 SELECT 語句中的所有匹配行。
在您的第一個查詢中,該
WHERE
子句沒有匹配項,因此該語句的前半部分沒有要返回的行,但您的後半部分UNION
是一個硬編碼值,該值對錶中的每一行重複但隨後進行了重複數據刪除由UNION
操作員,最終導致單行。正如您所注意到的,當您使用原始語句的後半部分直接查詢表時,您確實會得到一行,其中包含
test
為表中每一行重複的值。這是因為您不再使用UNION
之前對結果進行重複數據刪除的運算符。正如前面提到的 MySQL 文件引用中所指定的,如果您改用
UNION ALL
運算符,則不會刪除重複項,並且您將收到所有行,如預期的那樣,重複值為test
. 例如SELECT password FROM users WHERE username='' UNION ALL SELECT 'test' FROM users
請注意,這也是大多數現代關係數據庫系統中該運算符的常見行為。