where子句在sql中用于過濾數據,通過條件表達式選擇滿足條件的行。1.基礎排除使用not操作符,如not in排除指定值;2.多條件排除可用and或or組合,注意括號確保優先級;3.NULL值需用is not null排除;4.范圍排除用not between;5.模糊排除用not like配合通配符;此外還可結合distinct、group by、row_number()等實現去重,同時注意索引優化、避免函數和類型轉換以提升性能。
直接說吧,WHERE子句在SQL里就是個過濾器,你想篩掉啥,就用它。
根據標題詳細展開說明解決該問題
WHERE 后面跟的是條件表達式,只有滿足條件的行才會被選中。排除數據,本質上就是構造一個“不滿足”的條件。
-
基礎排除:NOT 操作符
最直接的方式就是使用 NOT 操作符。比如,你想排除 id 為 1, 2, 3 的數據:
select * FROM your_table WHERE NOT id IN (1, 2, 3);
這里,IN (1, 2, 3) 選擇了 id 為 1, 2, 或者 3 的行,NOT IN 就反過來,選擇了 id 不是 1, 2, 3 的行。
-
多條件排除:AND 和 OR 的巧妙運用
如果你的排除條件比較復雜,需要組合多個條件,AND 和 OR 就派上用場了。
比如,你想排除 status 為 ‘pending’ 并且 create_time 在 ‘2023-01-01’ 之前的數據:
SELECT * FROM your_table WHERE NOT (status = 'pending' AND create_time < '2023-01-01');
注意這里的括號,它確保了 AND 操作的優先級高于 NOT。
或者,你想排除 status 為 ‘pending’ 或者 status 為 ‘rejected’ 的數據:
SELECT * FROM your_table WHERE status != 'pending' AND status != 'rejected';
這里不能直接用NOT (status = ‘pending’ OR status = ‘rejected’),因為可能存在status為NULL的情況,導致結果不符合預期。
-
NULL 值的排除
NULL 值是個特殊的存在,不能直接用 = 或者 != 來判斷。你需要使用 IS NULL 和 IS NOT NULL。
比如,你想排除 email 為 NULL 的數據:
SELECT * FROM your_table WHERE email IS NOT NULL;
-
范圍排除:BETWEEN 和 NOT BETWEEN
如果你想排除某個范圍的數據,可以使用 BETWEEN 和 NOT BETWEEN。
比如,你想排除 price 在 10 到 100 之間的數據:
SELECT * FROM your_table WHERE price NOT BETWEEN 10 AND 100;
-
模糊排除:LIKE 和 NOT LIKE
如果你想排除包含某個模式的數據,可以使用 LIKE 和 NOT LIKE。
比如,你想排除 name 包含 ‘test’ 的數據:
SELECT * FROM your_table WHERE name NOT LIKE '%test%';
% 是通配符,表示任意字符。
SQL排除重復數據的幾種方法?
-
DISTINCT 關鍵字
最簡單的方法就是使用 DISTINCT 關鍵字。它會返回指定列的唯一值。
SELECT DISTINCT column1, column2 FROM your_table;
但是,DISTINCT 只能作用于整個行,也就是說,只有當 column1 和 column2 的值都相同時,才會被認為是重復行。
-
GROUP BY 子句
GROUP BY 子句可以將具有相同值的行分組在一起。然后,你可以使用聚合函數(比如 count、SUM、AVG 等)來處理這些分組。
SELECT column1, column2, COUNT(*) FROM your_table GROUP BY column1, column2 HAVING COUNT(*) > 1;
這個查詢會返回 column1 和 column2 的值,以及它們的重復次數。HAVING COUNT(*) > 1 表示只返回重復的行。
-
ROW_NUMBER() 函數
ROW_NUMBER() 函數可以為結果集中的每一行分配一個唯一的序號。你可以使用這個序號來刪除重復的行。
WITH RowNumCTE AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY column1, column2 ORDER BY (SELECT 0)) AS RowNum FROM your_table ) DELETE FROM RowNumCTE WHERE RowNum > 1;
這個查詢首先使用 ROW_NUMBER() 函數為每一行分配一個序號,然后刪除序號大于 1 的行,也就是重復的行。PARTITION BY column1, column2 表示按照 column1 和 column2 進行分組,ORDER BY (SELECT 0) 只是為了保證語法正確,實際上并不影響結果。
-
使用臨時表
你可以先將唯一的數據插入到臨時表中,然后清空原表,再將臨時表的數據插入到原表中。
-- 創建臨時表 CREATE TEMPORARY TABLE temp_table AS SELECT DISTINCT column1, column2 FROM your_table; -- 清空原表 TRUNCATE TABLE your_table; -- 將臨時表的數據插入到原表 INSERT INTO your_table SELECT * FROM temp_table; -- 刪除臨時表 DROP TEMPORARY TABLE temp_table;
這種方法比較繁瑣,但是可以處理一些特殊情況。
-
利用唯一索引
如果你的表中已經存在唯一索引,那么插入重復數據時會報錯。你可以利用這個特性來刪除重復數據。
-- 創建唯一索引 CREATE UNIQUE INDEX unique_index ON your_table (column1, column2); -- 忽略插入錯誤 INSERT IGNORE INTO your_table (column1, column2) SELECT column1, column2 FROM your_table; -- 刪除重復數據 DELETE FROM your_table WHERE id NOT IN (SELECT MIN(id) FROM your_table GROUP BY column1, column2);
這種方法的前提是你的表中已經存在唯一索引,或者可以創建唯一索引。
SQL中WHERE子句的性能優化技巧有哪些?
-
索引的使用
這是最基本也是最重要的優化技巧。在 WHERE 子句中使用的列,如果經常被查詢,那么應該為其創建索引。
索引就像一本書的目錄,可以幫助數據庫快速找到需要的數據,而不需要掃描整個表。
CREATE INDEX index_name ON your_table (column_name);
但是,索引也不是越多越好。索引會占用額外的存儲空間,并且在插入、更新、刪除數據時,需要維護索引,會降低性能。所以,應該只為經常被查詢的列創建索引。
-
避免在 WHERE 子句中使用函數
如果在 WHERE 子句中使用函數,會導致索引失效。因為數據庫無法使用索引來查找函數的結果。
比如,你想查詢 create_time 在 ‘2023-01-01’ 之后的數據:
-- 不好的寫法 SELECT * FROM your_table WHERE date(create_time) > '2023-01-01'; -- 好的寫法 SELECT * FROM your_table WHERE create_time > '2023-01-01 00:00:00';
第一種寫法使用了 DATE() 函數,會導致索引失效。第二種寫法直接比較 create_time 的值,可以使用索引。
-
避免使用 OR 操作符
在某些情況下,使用 OR 操作符會導致索引失效。
比如,你想查詢 status 為 ‘pending’ 或者 status 為 ‘rejected’ 的數據:
-- 不好的寫法 SELECT * FROM your_table WHERE status = 'pending' OR status = 'rejected'; -- 好的寫法 SELECT * FROM your_table WHERE status IN ('pending', 'rejected');
第一種寫法使用了 OR 操作符,可能會導致索引失效。第二種寫法使用了 IN 操作符,可以使用索引。
當然,這并不是絕對的。在某些情況下,使用 OR 操作符的性能可能更好。你需要根據實際情況進行測試。
-
避免使用 != 或者 操作符
在某些情況下,使用 != 或者 操作符會導致索引失效。
比如,你想查詢 status 不為 ‘pending’ 的數據:
-- 不好的寫法 SELECT * FROM your_table WHERE status != 'pending'; -- 好的寫法 SELECT * FROM your_table WHERE status IS NULL OR status <> 'pending';
第一種寫法使用了 != 操作符,可能會導致索引失效。第二種寫法使用了 IS NULL 和 操作符,可以使用索引。
同樣,這并不是絕對的。你需要根據實際情況進行測試。
-
使用 EXISTS 代替 IN
在某些情況下,使用 EXISTS 代替 IN 可以提高性能。
比如,你想查詢 your_table 中存在于 another_table 中的數據:
-- 不好的寫法 SELECT * FROM your_table WHERE id IN (SELECT id FROM another_table); -- 好的寫法 SELECT * FROM your_table WHERE EXISTS (SELECT 1 FROM another_table WHERE another_table.id = your_table.id);
EXISTS 只會檢查子查詢是否返回任何行,而 IN 會將子查詢的結果加載到內存中。所以,在子查詢的結果集比較大的情況下,使用 EXISTS 的性能更好。
-
優化子查詢
如果 WHERE 子句中包含子查詢,那么應該盡量優化子查詢。
比如,你可以使用 JOIN 代替子查詢。
-- 不好的寫法 SELECT * FROM your_table WHERE column1 IN (SELECT column1 FROM another_table WHERE column2 = 'value'); -- 好的寫法 SELECT your_table.* FROM your_table JOIN another_table ON your_table.column1 = another_table.column1 WHERE another_table.column2 = 'value';
JOIN 可以將兩個表連接在一起,避免了多次查詢數據庫。
-
使用 LIMIT 限制結果集
如果只需要一部分數據,可以使用 LIMIT 限制結果集的大小。
SELECT * FROM your_table WHERE column1 = 'value' LIMIT 10;
這樣可以減少數據庫的負擔,提高查詢速度。
-
避免在WHERE條件中使用類型轉換
當WHERE條件涉及不同數據類型的比較時,數據庫可能會嘗試進行隱式類型轉換,這通常會導致索引失效。確保比較的數據類型一致,或者顯式地進行類型轉換,但要小心,顯式轉換也可能導致索引失效,需要具體情況具體分析。
SQL中WHERE子句與HAVING子句的區別?
-
作用對象不同
WHERE 子句用于過濾行,它作用于表中的每一行,決定哪些行會被選中。
HAVING 子句用于過濾分組,它作用于 GROUP BY 子句創建的每個分組,決定哪些分組會被選中。
-
使用時機不同
WHERE 子句在分組之前進行過濾,也就是說,它在 GROUP BY 子句之前執行。
HAVING 子句在分組之后進行過濾,也就是說,它在 GROUP BY 子句之后執行。
-
可以使用的條件不同
WHERE 子句可以使用任何列作為條件,包括未分組的列。
HAVING 子句只能使用分組列或者聚合函數作為條件。
-
是否需要 GROUP BY 子句
WHERE 子句不需要 GROUP BY 子句。
HAVING 子句必須與 GROUP BY 子句一起使用。
舉個例子,你想查詢每個部門的平均工資,并且只返回平均工資大于 5000 的部門:
SELECT department, AVG(salary) FROM employees GROUP BY department HAVING AVG(salary) > 5000;
在這個例子中,GROUP BY department 將員工按照部門進行分組,AVG(salary) 計算每個部門的平均工資,HAVING AVG(salary) > 5000 過濾掉平均工資小于等于 5000 的部門。
如果你想查詢工資大于 3000 的員工,并且只返回這些員工所在的部門的平均工資大于 5000 的部門:
SELECT department, AVG(salary) FROM employees WHERE salary > 3000 GROUP BY department HAVING AVG(salary) > 5000;
在這個例子中,WHERE salary > 3000 過濾掉工資小于等于 3000 的員工,GROUP BY department 將剩余的員工按照部門進行分組,AVG(salary) 計算每個部門的平均工資,HAVING AVG(salary) > 5000 過濾掉平均工資小于等于 5000 的部門。
總結一下:WHERE 過濾行,HAVING 過濾分組。WHERE 在分組前執行,HAVING 在分組后執行。WHERE 可以使用任何列作為條件,HAVING 只能使用分組列或者聚合函數作為條件。