SQL使用WHERE條件語句的項目實踐
引言
在結(jié)構(gòu)化查詢語言 (SQL)語句中,WHERE子句限制了給定操作會影響哪些行。它們通過定義特定的條件(稱為搜索條件)來實現(xiàn)這一點,每一行都必須滿足這些條件才能受到操作的影響。
本指南將介紹WHERE子句中使用的通用語法。它還將概述如何在單個WHERE子句中組合多個搜索條件謂詞以更細(xì)粒度的方式過濾數(shù)據(jù),以及如何使用NOT操作符排除而不是包含滿足給定搜索條件的行。
雖然本指南在示例中只使用SELECT語句,但這里解釋的概念可以用于許多SQL操作。事實上,WHERE子句是UPDATE和DELETE操作的關(guān)鍵組成部分。
前期準(zhǔn)備
為了學(xué)習(xí)本指南,你需要一臺運行某種使用SQL的關(guān)系數(shù)據(jù)庫管理系統(tǒng)(RDBMS)的計算機。
注意:請注意,許多RDBMS使用它們自己獨特的SQL實現(xiàn)。雖然本教程中概述的命令適用于大多數(shù)RDBMS,但如果你在MySQL以外的系統(tǒng)上測試它們,確切的語法或輸出可能會有所不同。
你還需要一個裝載了一些示例數(shù)據(jù)的數(shù)據(jù)庫和表,可以在其中練習(xí)使用相關(guān)命令。
連接到MySQL并設(shè)置一個示例數(shù)據(jù)庫
如果SQL數(shù)據(jù)庫系統(tǒng)運行在遠(yuǎn)程服務(wù)器上,請從本地設(shè)備SSH到服務(wù)器:
ssh sammy@your_server_ip
然后打開MySQL服務(wù)器提示符,將==sammy==替換為你的MySQL用戶賬戶的名稱:
mysql -u sammy -p
創(chuàng)建一個名為where_db的數(shù)據(jù)庫:
CREATE DATABASE where_db;
如果數(shù)據(jù)庫成功創(chuàng)建,您將收到這樣的輸出:
OutputQuery OK, 1 row affected (0.01 sec)
要選擇where_db數(shù)據(jù)庫,運行以下USE語句:
USE where_db;
OutputDatabase changed
選擇where_db后,在其中創(chuàng)建一個表。
為了理解本指南中使用的示例,假設(shè)您在當(dāng)?shù)氐母郀柗蚯驁鼋?jīng)營高爾夫聯(lián)賽。你決定跟蹤聯(lián)盟球員參加郊游時的個人表現(xiàn)信息。為此,您決定將信息存儲在SQL數(shù)據(jù)庫中。
你決定這個表需要6列:
name:每個高爾夫球手的名字,使用varchar數(shù)據(jù)類型表示,不超過20個字符rounds_played:每個高爾夫球手打完的總回合數(shù),用int數(shù)據(jù)類型表示best:每位高爾夫球手在單次比賽中的最佳或最低得分,也用int表示。worst:每位高爾夫球手在單次比賽中的最差或最高得分,同樣用int表示average:每個高爾夫球手在他們打過的幾輪中得分的近似平均值。這一列將保存decimal類型的值,限制為最多4位,其中一位在小數(shù)點的右側(cè)wins:每個高爾夫球手在比賽小組中得分最低的輪數(shù),用int類型表示
運行下面的CREATE TABLE語句來創(chuàng)建一個名為golfers的表,它包含以下6列:
CREATE TABLE golfers ( name varchar(20), rounds_played int, best int, worst int, average decimal (4,1), wins int );
然后加載包含一些示例數(shù)據(jù)的golfers表。運行下面的INSERT INTO操作來添加代表7名聯(lián)賽高爾夫球手的7行數(shù)據(jù):
INSERT INTO golfers
VALUES
('George', 22, 68, 103, 84.6, 3),
('Pat', 25, 65, 74, 68.7, 9),
('Grady', 11, 78, 118, 97.6, 0),
('Diane', 23, 70, 92, 78.8, 1),
('Calvin', NULL, 63, 76, 68.5, 7),
('Rose', NULL, 69, 84, 76.7, 4),
('Raymond', 18, 67, 92, 81.3, 1);請注意,其中兩行rounds_played的值是NULL。出于本教程的目的,假設(shè)這些高爾夫球手沒有報告他們打了多少輪,因此這些值被記錄為NULL。
你可能還注意到,每個高爾夫球手的best值小于他們的worst值。這是因為,在常見的高爾夫規(guī)則中,高爾夫球手的得分是由他們將球打入球場每個洞所需的擊球次數(shù)決定的,總擊球次數(shù)最少的人就是獲勝者。因此,與大多數(shù)其他運動不同,高爾夫球手的最佳分?jǐn)?shù)會比最差分?jǐn)?shù)低。
有了這些,你就可以開始學(xué)習(xí)如何在SQL中使用WHERE子句了。
使用WHERE子句過濾數(shù)據(jù)
在SQL中,語句是任何發(fā)送到數(shù)據(jù)庫系統(tǒng)的操作,它將執(zhí)行某種任務(wù),如創(chuàng)建表,插入或刪除數(shù)據(jù),或更改列或表的結(jié)構(gòu)。SQL語句是由各種子句,由特定的關(guān)鍵字和他們需要的信息。
正如引言中提到的,WHERE子句允許你過濾掉受SQL操作影響的某些行數(shù)據(jù)。在查詢中,WHERE之后跟上查詢條件,如以下示例:
SELECT columns_to_query FROM table_to_query WHERE search_condition;
WHERE關(guān)鍵字后面是一個搜索條件。一個搜索條件是由一個或多個謂詞或表達式組成的集合,這些謂詞或表達式可以計算一個或多個值表達式并返回“true”、“false”或“unknown”的結(jié)果。注意,在搜索條件只包含一個謂詞的情況下,術(shù)語“搜索條件”和“謂詞”是同義詞。
WHERE子句搜索條件中的謂詞可以有多種形式,但它們通常遵循以下語法:
. . . WHERE column_name OPERATOR value_expression . . .
在SQL中,值表達式——有時也稱為標(biāo)量表達式——是任何返回單個值的表達式。值表達式可以是字面量,比如字符串或數(shù)值,也可以是數(shù)學(xué)表達式。不過,大多數(shù)情況下,在WHERE子句的搜索條件中,至少有一個值表達式是列名。
當(dāng)運行包含WHERE子句的SQL查詢時,數(shù)據(jù)庫管理系統(tǒng)將對FROM子句定義的邏輯表中的每一行應(yīng)用搜索條件。然后,它將只返回所有謂詞在搜索條件中求值為“true”的行。
為了說明這個想法,運行下面的查詢。這將返回golfers表的name列中的所有值:
SELECT name FROM golfers WHERE (2 + 2) = 4;
這個查詢包含一個WHERE子句,但它沒有指定列名,而是使用(2 + 2)作為第一個值表達式,并測試它是否等于第二個值表達式4。因為(2 + 2) 總是等于4,所以對于每一行,這個搜索條件都計算為true。因此,結(jié)果集中的每一行都會被返回:
Output+---------+ | name | +---------+ | George | | Pat | | Grady | | Diane | | Calvin | | Rose | | Raymond | +---------+ 7 rows in set (0.01 sec)
這個WHERE子句不是很有用,因為它總是求值為“true”并總是返回表中的每一行。如前所述,在WHERE子句搜索條件中,通常至少使用一個列名作為值表達式。當(dāng)運行查詢時,數(shù)據(jù)庫系統(tǒng)將依次對每一行應(yīng)用搜索條件。通過在搜索條件中提供列名作為值表達式,你告訴DBMS使用該列中每行的值作為迭代搜索條件時的值表達式。
以下查詢的WHERE子句對每一行應(yīng)用了比前一個示例更排他的搜索條件。它將返回任何wins列值等于1的行中的name和wins值:
SELECT name, wins FROM golfers WHERE wins = 1;
只有兩名高爾夫球手剛好贏了一輪,因此這個查詢只返回這兩行:
Output+---------+------+ | name | wins | +---------+------+ | Diane | 1 | | Raymond | 1 | +---------+------+ 2 rows in set (0.01 sec)
前面的例子使用等號(=)測試是否兩個值表達式是等價的,但您使用的運營商取決于您想要使用什么類型的謂詞過濾結(jié)果集。
SQL標(biāo)準(zhǔn)定義了18種類型的謂詞,盡管并不是所有的SQL實現(xiàn)都包含這些謂詞。下面是5種最常用的謂詞類型,以及對每種類型及其使用的操作符的簡要說明。
比較
比較謂詞使用比較運算符比較一個值(在查詢,通常值在一個指定的列)。這6個比較運算符是:
=:測試兩個值是否相等
SELECT name FROM golfers WHERE name = 'George';
Output+--------+ | name | +--------+ | George | +--------+ 1 row in set (0.00 sec)
<>:測試兩個值是否不相等
SELECT name, wins FROM golfers WHERE wins <> 1;
Output+--------+------+ | name | wins | +--------+------+ | George | 3 | | Pat | 9 | | Grady | 0 | | Calvin | 7 | | Rose | 4 | +--------+------+ 5 rows in set (0.00 sec)
<:測試第一個值是否小于第二個值
SELECT name, wins FROM golfers WHERE wins < 1;
Output+-------+------+ | name | wins | +-------+------+ | Grady | 0 | +-------+------+ 1 row in set (0.00 sec)
>:測試第一個值是否大于第二個值
SELECT name, wins FROM golfers WHERE wins > 1;
Output+--------+------+ | name | wins | +--------+------+ | George | 3 | | Pat | 9 | | Calvin | 7 | | Rose | 4 | +--------+------+ 4 rows in set (0.00 sec)
<=:測試第一個值是否小于或等于第二個
SELECT name, wins FROM golfers WHERE wins <= 1;
Output+---------+------+ | name | wins | +---------+------+ | Grady | 0 | | Diane | 1 | | Raymond | 1 | +---------+------+ 3 rows in set (0.00 sec)
>=:測試第一個值是否大于或等于第二個值
SELECT name, wins FROM golfers WHERE wins >= 1;
Output+---------+------+ | name | wins | +---------+------+ | George | 3 | | Pat | 9 | | Diane | 1 | | Calvin | 7 | | Rose | 4 | | Raymond | 1 | +---------+------+ 6 rows in set (0.00 sec)
Null(IS NULL)
使用IS NULL操作符的謂詞測試給定列中的值是否為NULL。如果是,則謂詞的計算結(jié)果為“true”,結(jié)果集中就包含了這一行:
SELECT name, rounds_played FROM golfers WHERE rounds_played IS NULL;
Output+--------+---------------+ | name | rounds_played | +--------+---------------+ | Calvin | NULL | | Rose | NULL | +--------+---------------+ 2 rows in set (0.00 sec)
區(qū)間(BETWEEN)
范圍謂詞使用BETWEEN操作符來測試指定的列值是否落在兩個值表達式之間:
SELECT name, best FROM golfers WHERE best BETWEEN 67 AND 73;
Output+---------+------+ | name | best | +---------+------+ | George | 68 | | Diane | 70 | | Rose | 69 | | Raymond | 67 | +---------+------+ 4 rows in set (0.00 sec)
包含(IN)
成員謂詞使用IN操作符來測試一個值是否是給定集合的成員:
SELECT name, best FROM golfers WHERE best IN (65, 67, 69, 71);
Output+---------+------+ | name | best | +---------+------+ | Pat | 65 | | Rose | 69 | | Raymond | 67 | +---------+------+ 3 rows in set (0.00 sec)
通配符(%和_)
模式匹配謂詞使用LIKE操作符來測試一個值是否匹配包含一個或多個通配符的字符串模式,也稱為通配符。SQL定義了兩個通配符,%和_:
_: 下劃線表示單個未知字符
SELECT name, rounds_played FROM golfers WHERE rounds_played LIKE '2_';
Output+--------+---------------+ | name | rounds_played | +--------+---------------+ | George | 22 | | Pat | 25 | | Diane | 23 | +--------+---------------+ 3 rows in set (0.00 sec)
%: 百分比符號表示零個或多個未知字符
SELECT name, rounds_played FROM golfers WHERE name LIKE 'G%';
Output+--------+---------------+ | name | rounds_played | +--------+---------------+ | George | 22 | | Grady | 11 | +--------+---------------+ 2 rows in set (0.00 sec)
用AND和OR組合多個查詢條件
有時候,你需要比使用單個搜索條件謂詞的WHERE子句提供的更細(xì)粒度的過濾結(jié)果。另一方面,也可能有滿足多個搜索條件之一的行在結(jié)果集中是可接受的。在這種情況下,你可以編寫包含多個謂詞的WHERE子句,分別使用AND或OR操作符。
要開始使用這些操作符,請運行以下查詢,它從golfers表的name、best、worst和average列中返回值。它的WHERE子句包含兩個查詢條件,由AND分隔:
SELECT name, best, worst, average FROM golfers WHERE best < 70 AND worst < 96;
第一個謂詞測試每一行的best值是否小于70,而第二個測試每一行的worst價值是否小于96。如果任何一個測試的結(jié)果為“false”,則該行不會返回到結(jié)果集中:
Output+---------+------+-------+---------+ | name | best | worst | average | +---------+------+-------+---------+ | Pat | 65 | 74 | 68.7 | | Calvin | 63 | 76 | 68.5 | | Rose | 69 | 84 | 76.7 | | Raymond | 67 | 92 | 81.3 | +---------+------+-------+---------+ 4 rows in set (0.00 sec)
接下來,運行以下查詢。這與前面的例子相同,只是它用OR操作符而不是AND來分隔兩個謂詞:
SELECT name, best, worst, average FROM golfers WHERE best < 70 OR worst < 96;
因為只有一個謂詞的求值為“true”才能返回一行,所以這個結(jié)果集比前面的例子多了兩行:
Output+---------+------+-------+---------+ | name | best | worst | average | +---------+------+-------+---------+ | George | 68 | 103 | 84.6 | | Pat | 65 | 74 | 68.7 | | Diane | 70 | 92 | 78.8 | | Calvin | 63 | 76 | 68.5 | | Rose | 69 | 84 | 76.7 | | Raymond | 67 | 92 | 81.3 | +---------+------+-------+---------+ 6 rows in set (0.00 sec)
你可以在一個WHERE子句中包含任意數(shù)量的謂詞,只要你用正確的語法將它們組合起來。然而,隨著搜索條件變得越來越復(fù)雜,預(yù)測它們將過濾哪些數(shù)據(jù)變得越來越困難。
需要注意的是,數(shù)據(jù)庫系統(tǒng)通常優(yōu)先考慮AND操作符。這意味著任何由AND操作符分隔的謂詞(或在兩個以上謂詞的情況下的操作符)都被視為一個單獨的、隔離的搜索條件,在WHERE子句中的任何其他謂詞之前進行測試。
為了說明問題,運行下面的查詢,它從name、average、worst和rounds_played列中返回滿足WHERE子句中定義的搜索條件的任何行:
SELECT name, average, worst, rounds_played FROM golfers WHERE average < 85 OR worst < 95 AND rounds_played BETWEEN 19 AND 23;
這個查詢首先測試由AND操作符分隔的謂詞是否worst < 95和rounds_played BETWEEN 19 AND 23——在當(dāng)前迭代中,這兩個值都為“true”。如果是,那么該行將出現(xiàn)在結(jié)果集中。但是如果任何一個求值為“false”,查詢將檢查當(dāng)前行的average值是否小于85。如果是,則返回該行:
Output+---------+---------+-------+---------------+ | name | average | worst | rounds_played | +---------+---------+-------+---------------+ | George | 84.6 | 103 | 22 | | Pat | 68.7 | 74 | 25 | | Diane | 78.8 | 92 | 23 | | Calvin | 68.5 | 76 | NULL | | Rose | 76.7 | 84 | NULL | | Raymond | 81.3 | 92 | 18 | +---------+---------+-------+---------------+ 6 rows in set (0.00 sec)
您可以通過將兩個或多個查詢條件包裝在括號中來確定它們的優(yōu)先級。下面的示例與前一個相同,但它封裝了average < 85和worst < 95查詢條件,用OR操作符分隔,放在括號中:
SELECT name, average, worst, rounds_played FROM golfers WHERE (average < 85 OR worst < 95) AND rounds_played BETWEEN 19 AND 23;
因為前兩個謂詞被圓括號包圍,后續(xù)的AND操作符將它們視為一個離散的搜索條件,必須求值為“true”。如果這兩個謂詞- average < 85和worst < 95——求值為“false”,那么整個搜索條件求值為“false”,查詢會立即從結(jié)果集中刪除這一行,然后再繼續(xù)求值下一行。
然而,如果前兩個謂詞中的任何一個求值為“true”,查詢就會測試給定高爾夫球手的rounds_played值是否在19到23之間。如果是,則在結(jié)果集中返回這一行:
Output+--------+---------+-------+---------------+ | name | average | worst | rounds_played | +--------+---------+-------+---------------+ | George | 84.6 | 103 | 22 | | Diane | 78.8 | 92 | 23 | +--------+---------+-------+---------------+ 2 rows in set (0.00 sec)
結(jié)果表明,通過優(yōu)先級的謂詞集和包裝在括號,否則相同的查詢可以返回結(jié)果集明顯不同。
盡管并不總是需要這樣做,但建議在單個搜索條件中組合兩個以上謂詞時始終使用括號。這樣做有助于使查詢更可讀、更容易理解。
用NOT排除結(jié)果
到目前為止,本指南的所有示例都集中在如何使用WHERE子句編寫查詢,在結(jié)果集中只包含滿足指定搜索條件的行。然而,你可以通過在WHERE子句中包含NOT操作符來編寫排除特定行的查詢。
范圍、會員和模式匹配謂詞的條款,包括NOT操作符通常遵循這一語法:
. . . WHERE column_name NOT OPERATOR value_expression . . .
為了說明這一點,運行下面的查詢。這將返回golfers表的name列的值,但其WHERE子句中的NOT操作符將導(dǎo)致DBMS排除所有匹配通配符模式的行:
SELECT name FROM golfers WHERE name NOT LIKE 'R%';
Output+--------+ | name | +--------+ | George | | Pat | | Grady | | Diane | | Calvin | +--------+ 5 rows in set (0.00 sec)
當(dāng)將NOT操作符添加到IS NULL謂詞時,情況略有不同。在這種情況下,你可以將NOT放在IS和NULL之間,如下面的例子所示。這個查詢返回所有rounds_played值不為Null的高爾夫球手的name和rounds_played值:
SELECT name, rounds_played FROM golfers WHERE rounds_played IS NOT NULL;
Output+---------+---------------+ | name | rounds_played | +---------+---------------+ | George | 22 | | Pat | 25 | | Grady | 11 | | Diane | 23 | | Raymond | 18 | +---------+---------------+ 5 rows in set (0.00 sec)
你也可以將NOT操作符緊跟在WHERE關(guān)鍵字之后。如果你根據(jù)是否滿足多個搜索條件來排除行,這很有用,如下面的示例查詢返回golfers的name、average、best和wins值:
SELECT name, average, best, wins FROM golfers WHERE NOT (average < 80 AND best < 70) OR wins = 9;
Output+---------+---------+------+------+ | name | average | best | wins | +---------+---------+------+------+ | George | 84.6 | 68 | 3 | | Pat | 68.7 | 65 | 9 | | Grady | 97.6 | 78 | 0 | | Diane | 78.8 | 70 | 1 | | Raymond | 81.3 | 67 | 1 | +---------+---------+------+------+ 5 rows in set (0.00 sec)
請注意結(jié)果集的第二行。帕特的“平均”分?jǐn)?shù)不到80分,她的“最佳”分?jǐn)?shù)也不到70分。然而,她的行仍然包含在結(jié)果集中,因為NOT操作符只是對括號內(nèi)的搜索條件求反。
回想一下,當(dāng)您將由AND或OR分隔的多個謂詞包裝在括號中時,SQL將優(yōu)先考慮這些謂詞,并將它們視為單個隔離的搜索條件。因此,NOT操作符只排除基于前兩個謂詞的行: average < 80和best < 70。但是它包含基于第三個謂詞的行,wins = 9。
你可以重寫這個查詢,根據(jù)第三個條件和前兩個條件將它們都包含在括號中,如下所示:
SELECT name, average, best, wins FROM golfers WHERE NOT ((average < 80 AND best < 70) OR wins = 9);
Output+---------+---------+------+------+ | name | average | best | wins | +---------+---------+------+------+ | George | 84.6 | 68 | 3 | | Grady | 97.6 | 78 | 0 | | Diane | 78.8 | 70 | 1 | | Raymond | 81.3 | 67 | 1 | +---------+---------+------+------+ 4 rows in set (0.00 sec)
根據(jù)SQL實現(xiàn)的不同,如果你在比較操作符之前包含NOT,數(shù)據(jù)庫系統(tǒng)可能會認(rèn)為查詢語法無效。舉個例子,試著運行這個查詢:
SELECT name FROM golfers WHERE name NOT = 'Grady';
對于MySQL及其衍生版本,這將導(dǎo)致錯誤:
OutputERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '= 'Grady'' at line 1
這個錯誤的原因是NOT操作符通常不與比較操作符(=,<>, <, <, <=, >和>=)一起使用,因為你可以通過將一個比較操作符替換為另一個比較操作符來實現(xiàn)相反的效果,該比較操作符將返回第一個比較操作符將排除的行。例如,你可以將等價運算符(=)替換為不等價運算符(<>)。
總結(jié)
通過閱讀本指南,你學(xué)習(xí)了如何編寫WHERE子句,使查詢只返回滿足指定條件的行。你還學(xué)習(xí)了如何在單個查詢中組合多個謂詞和搜索條件,以及如何使用NOT關(guān)鍵字從結(jié)果集中排除信息。
雖然這里顯示的命令在大多數(shù)關(guān)系型數(shù)據(jù)庫上都可以工作,但請注意,每個SQL數(shù)據(jù)庫都使用自己獨特的語言實現(xiàn)。關(guān)于每個命令及其所有選項的更完整描述,讀者可以查閱相應(yīng)DBMS的官方文檔。
到此這篇關(guān)于SQL使用WHERE條件語句的項目實踐的文章就介紹到這了,更多相關(guān)SQL使用WHERE條件語句內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL學(xué)習(xí)筆記之?dāng)?shù)據(jù)定義表約束,分頁方法總結(jié)
這篇文章主要介紹了MySQL學(xué)習(xí)筆記之?dāng)?shù)據(jù)定義表約束,分頁方法,結(jié)合實例形式總結(jié)分析了數(shù)據(jù)定義、主鍵、外鍵、自增長、約束等概念與用法,并給出了關(guān)于分頁的實例與相關(guān)操作技巧,需要的朋友可以參考下2016-09-09
基于mysql+mycat搭建穩(wěn)定高可用集群負(fù)載均衡主備復(fù)制讀寫分離操作
這篇文章主要介紹了基于mysql+mycat搭建穩(wěn)定高可用集群負(fù)載均衡主備復(fù)制讀寫分離操作,需要的朋友可以參考下2018-09-09
解決MySQL報錯:The last packet sent successfu
這篇文章主要介紹了解決MySQL報錯:The last packet sent successfully to the server was 0 milliseconds ago問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12

