select select_list[ into new_table ]from table_source[ where search_condition ][ group by broup_by_exPRession ][ having search_condition ][order by order_by_expression [ asc | desc ]
select查詢語句中的主要參數說明如下
select_list:查詢的列或者表達式的列表,用逗號進行分隔。 new_table:新的表名。 table_source:要查詢的表。如果是多個表,用逗號進行分隔。 search_condition:查詢條件。 group_by_expression:分組表達式。 order_by_expression:排序表達式。 asc:升序排序。 desc:降序排序。
select查詢語句字句的功能列表
子句 | 主要功能 | 是否必需 |
select | 指定由查詢返回的列 | 是 |
from | 指定要查詢的表 | 是 |
into | 創建新表并將結果行插入新表中 | 否 |
where | 查詢條件 | 否 |
group by | 對查詢結果進行分組 | 否 |
order by | 對查詢結果進行排序 | 否 |
having | 對查詢結果進行篩選 | 否 |
選擇列表用于定義select語句的結果集中的列
1、* 查詢所有列:
select * from person
*就是結果集合,表示查詢person表中的所有列。
2、distinct 去除重復數據:
distinct是對所有列作用,也就是說,所有列都相同才算重復數據。
select distinct name from person
3、包含函數的查詢:
例如:
select count(*) from person
from子句實際上就是用逗號分隔的表名、視圖名和join字句的列表。使用from子句可以實現如下功能:
1、列出選擇列表和where子句引用的列所在的表和視圖。可以使用as子句為表和視圖指定別名。
2、聯接類型。這些類型由on子句中指定的聯接條件限定。
分配表名時可以使用如下形式
需要特別說明的是,如果為表分配了別名,那么T-SQL語句中對該表的所有顯示引用都必須使用別名,而不能使用別名。
where子句可以篩選結果集的源表中的行。帶有where子句的select語句的結構如下:
select <字段列表> from <表名> where<條件表達式>
其中,條件表達式是由各種字段、常量、表達式、關系運算符、邏輯運算符和特殊的運算符組合起來的。
where子句中的運算符:
1、關系運算符
關系運算符用來表示兩個表達式之間的比較關系。
關系運算符 | 含義 |
= | 等于 |
< | 小于 |
> | 大于 |
!=(或<>) | 不等于 |
>= | 大于等于 |
<= | 小于等于 |
!> | 不大于 |
!< | 不小于 |
2、邏輯運算符
邏輯運算符用于表示兩個表達式之間的邏輯關系:
邏輯運算符 | 含義 |
not | 非(否) |
and | 與 |
or | 或 |
3、特殊運算符
特殊運算符 | 含義 |
% | 通配符,通常與like配合使用 |
_ | 通配符,代表嚴格的一個字符。where name like '_xxx'將查找以xxx結尾的所有4個字母的名字(sxxx,dxxx等) |
[] | 指定范圍([a-f])或集合([abcdefg])中的任何單個字符。where name like '[a-f]xxxx',將超找以abcdef開頭,xxxx結尾的字符。 |
[^] | 不屬于指定范圍的([a-f])或集合([abcdefg])的任何單個字符。 |
between | 定義一個取值范圍區間,使用and分開。between開始值與and結束值。 |
like | 字符串匹配 |
in | 一個字段的值是否在一組定義的值之中 |
exists | 子查詢有結果集返回(則子查詢返回True) |
not exists | 子查詢沒有結果集返回(則子查詢返回True) |
is null | 字段是否為null |
is not null | 字段是否不為null |
在WHERE子句中使用EXISTS(如果使用得當的話)可以大大提高性能。因為使用EXISTS時,只要找到和條件匹配的記錄,SQL Server就立即停止。假設有一個包含一百萬條記錄的表,并且在第三個記錄中找到了匹配的記錄,那么使用EXISTS選項將避免讀取999997條記錄!NOT EXISTS以同樣的方式工作。
為了最簡單地說明問題,我特地設計了一張這樣的表。
規則1:單值規則,跟在SELECT后面的列表,對于每個分組來說,必須返回且僅僅返回一個值。
典型的表現就是跟在SELECT后面的列,如果沒有使用聚合函數,必須出現在GROUP BY子句后面。
如下面這個查詢報錯:
因為對于按照部門分組之后,技術部分組有3個編號,銷售部分組有2個編號,你讓數據庫顯示哪個呢?
如果假設你使用聚合函數COUNT(編號)之后,對于每個部門分組,就只有一個值 - 該部門下的人數:
下面來實戰下,我們希望查詢出每個部門,最高工資的那個人的姓名,部門,工資。
Shit,出師不利。第一次實戰就錯誤了,我們來分析下。
很明顯,上面的姓名列是不符合單值規則的。我們的一廂情愿想法是,MAX(工資)之后,SQL Server就能自動幫我們返回不符合單值規則的'姓名'。但是很遺憾,SQL Server并沒有這么做。理由如下:
綜上所述,數據庫是不可能能夠根據我們輸入的一個聚合函數,就幫助我們判斷并顯示出不符合單值規則的列的。
對于MySQL來說,當有這種不符合單值規則的列時,默認是返回這一組結果的第一條記錄。而SQLite是返回最后一條。
因此,對于以上查詢,我們要另尋解決方案。
解決方案1:關聯子查詢
SELECT 姓名,部門,工資 FROM 工資表 AS T1WHERE NOT EXISTS (SELECT NULL FROM 工資表 AS T2 WHERE T1.部門 = T2.部門 AND T2.工資 > T1.工資)
輸出如下:
完全符合要求。對于上面的關聯子查詢,可以理解為:
遍歷工資表的所有記錄,查找不存在比當前記錄部門相同且工資還大的記錄。
雖然,關聯子查詢的語法非常簡單,但是性能并不好。因為對于每一條記錄,都要執行一次子查詢。
解決方案2:衍生表
使用衍生表的思路是,先執行一個子查詢,得到一個臨時結果集,然后用臨時結果集和原表進行INNER JOIN操作。就能得到最高工資的人的信息。
剛寫出這個SQL語句時,覺得非常妙,理解了之后覺得非常妙。
SELECT 姓名,T1.部門,工資 FROM 工資表 AS T1 INNER JOIN( SELECT 部門,MAX(工資) AS 最高 FROM 工資表 --執行查詢,先記錄兩個字段 部門-最高工資 GROUP BY 部門) AS T2 --衍生表T2ON T1.部門 = T2.部門 AND 工資 = 最高
衍生表的方式性能優于關聯子查詢,因為衍生表的方式只執行了一次子查詢。但是它需要一張臨時表來存儲臨時記錄。因此,這個方案也并不是最佳的解決方案。
解決方案3:使用JOIN + IS NULL
這是一個更妙的解決方案,當我們用一個外聯結去匹配記錄時,當匹配的記錄不存在,就會用NULL來代替相應的列。
我們先來看一條非常簡答的SQL語句:
從中你看到了什么?當T2表中,不存在比T1表中工資高的記錄時就返回NULL。
那么,那么,那么一個IS NULL是不是就解決問題了呢?
好妙,好妙的方法,讓人拍案叫絕的使用了OUTER JOIN。
JOIN解決方案適用于針對大量數據查詢并且可伸縮比較時。它總是能比基于子查詢的解決方案更好地適應數據量的變量。
解決方案4:對額外的列使用聚合函數
我們知道,GROUP BY時,SELECT列表必須返回的是單值,那么我們可不可以通過使用聚合函數,讓這個列返回單值呢?答案是可以的。
其實,返回的數據是有問題的,當工資相同時,它就返回按姓名從大到小排列的第一個姓名。也就是說,當工資相同時,它只能夠返回一條記錄。
我們將聚合函數換成MIN看看。
解決方案5:Row_Number() + OVER
WITH B AS ( SELECT row_number() OVER(PARTITION BY Name ORDER BY CreateTime) AS part ,Score, Name, CreateTime FROM xxx ) SELECT * FROM B WHERE Part = 1
輸出如下:
WHERE與HAVING的區別:
新聞熱點
疑難解答