因為是按照課本順序,所以把數據查詢放在數據更新之前,根據自身情況選擇學習順序。mysql和sqlite在表的查詢上的語法幾乎完全一樣,所有文中只給出的大部分都是mysql中運行的截圖。
先看下課本給出的格式:
select [all | distinct] <目標列表達式> [[as] <別名>] [,<目標列表達式> [[as] <別名>]]...
from <表名或視圖名> [,<表名或視圖名>...] | (<select 語句>) [as] <別名>
[where <條件表達式>]
[group by <列名> [having <條件表達式>]]
[order by <列名> [asc | desc]]
為了方便講解,將其分為五個部分:即select,from,where,groupBy,orderBy
注意:這五個部分使用是有順序的。例如:select * from test.test where TRUE order by id group by id;這樣是違規的。
先看下select的部分:
select [all | distinct] <目標列表達式> [[as] <別名>] [,<目標列表達式> [[as] <別名>]]...
distinct表示把重復的行去掉,all則保留,all為默認值。
目標列表達式的格式有三種:
(1). * 表示所有列
mysql/sqlite>select * from test.test;

(2). <列名>這個很簡單了。當涉及到多個表時,要在列名前加上表名,格式為 “<表名>.<列名>",就像對象引用屬性,很符合編程邏輯,列是表的屬性,表是數據庫的屬性。
mysql/sqlite>select test.name as Name,test1.address as addr from test,test1;

注意:這里的結果是是每個表的元組的笛卡爾積(即廣義笛卡爾積,是關系代數中的概念,見課本關系代數部分)。
(3).列名表達式,常量,聚集函數以及這三者組成的任意運算公式
例如:
mysql/sqlite>select id+1,'hello world' from test;
主要的聚集函數:
count(*) 統計元組個數
count([distinct] <列名>) 統計一列中的非空值的個數
sum/avg([distinct]<列名>) 計算一列值總和/平均值(列必須是數值型)
max/min([distinct]<列名>) 求一列值中最大/最小值
聚集函數與group by一起使用時會分組后的每組進行聚集運算,下面會詳細講解。
from部分比較簡單,先看下語法:
from <表名或視圖名> [,<表名或視圖名>...] | (<select 語句>) [as] <別名>
可以看到<select 語句>比較特殊,這里只講解這個的用法。
select 語句執行結果也是一個臨時表,所以可以作為另個一select的輸入表,但一定要給臨時表一個別名。
注意:書中把包含在一個select語句中的select語句稱為子查詢。並且子查詢只支持select .. from ... where..,即子查詢中不能使用group by 和order by,但在mysql和sqlite中卻支持完整的select子查詢,即可以使用group和order。
where部分比較多,但大部分都很好理解,從設計者角度出發,就是把from <表>送來的元組進行判斷,滿足條件就送到下一步處理,不滿足拋棄,繼續接受下一個元組。
看下語法:[where <條件表達式>]
條件表達式支持的查詢條件:
<1>.比較 =,>,<,>=,<=,!=,<>,!>,!<;
<2>.確定范圍 [not] between and
<3>.確定集合 [not] in
<4>.字符匹配 [not] like 書中只支持兩個:%代表任意長度的字符串,_ 代表任意單個字符。
<5>.空值 [not] is NULL #sqlite中 is 相當於=,但在mysql中是按照定義的
<6>.多重條件 and,or,not
實際產品中可能會有還有自己實現的運算符,可自行查看官方手冊,例如位運算符在注入中也可以使用到,過濾時要考慮全面。
操作數可以是常量,列名,子查詢語句。
常量和列名的實例如下:

上面講到子查詢語句可以用在from中,因為select的結果其實也是表,從編程角度來講,就是同一個類的對象。同樣子查詢語句也可以放在where和having中用作操作數。
例如:where id in (select id from test) #子查詢的結果必須為一列。
where id > (select id from test where name='test') #子查詢的結果必須為一行一列,即只有一個元素。
從編程的角度很好理解,在進行運算時如果類型不同要進行類型轉換,只有一列的表可以轉換成集合(可以使用in運算),只有一個元素的表可以轉換成一個常量.
另外子查詢還可以支持any(或some)和all謂詞,以及存在量詞exists:
any/all必須和比較運算符使用。例如: where id < any(select id from test) #表示小於集合中的某一個即為真
where id > all(select id from test) #表示大於集合中的所有才為真
所以從上面可以看到,這里子查詢必須是只有一列才可以轉換成集合。
exists對子查詢沒有什么要求,用法也很簡單。例如:where exitsts (select id,name from test)
子查詢表非空返回真,為空返回假
group by的部分會涉及到聚集函數,看下語法:
[group by <列名> [having <條件表達式>]]
書中定義的語句中只有一個列名,但現實產品基本都可以加多列,例如:group by id,name;
group by子句將經過where判斷后的送來的元組分組,值相等的為一組,並且分組后聚集函數(如果select部分使用了的話)將作用於每一組,即每一組都有一個函數值。
結合例子就很好理解:

沒有group by,就相當於只有一組。使用聚集函數結果肯定只有一行。
having可以加上判斷條件,從group by中滿足條件的組,在送往下一步處理(where子句是把從from送來的元組進行判斷),所以having中可以使用聚集函數,而where中不能使用聚集函數;
having中的條件判斷表達式和where中是一樣的">/</!=...in ... like ... and/or/not..."都支持。
需要注意的是,使用group by和聚集函數時,查詢結果表的行數(不考慮limit子句)就是分組個數,所以最好不要使用無關列。
例如:select id,name from test group by id; #這里僅對id進行了分組,name是無關列。
對id分組后得到兩組,所以結果有兩行,但每一組name的值其實有多個,一般選每個分組的第一個元組。
order by部分是最簡單的,即對上面的部分處理過后的表進行排序;
語法:[order by <列名> [asc | desc]]
同樣的,實際產品中order by也可以加多列,可以使用別名。asc/desc 表示升/降序,升序為默認值。

除了書中定義的上面五個部分,現實中的產品中普遍還有一個 limit 部分,作用在order by之后,用來從最終表中選取特定幾行。
語法:
limit [偏移量,] <選取行數> | <選取行數> offset [偏移量];
偏移量就是從第幾行開始選取。默認偏移量是0,代表從第一行開始,這里偏移量就像數組下表。
例如:mysql/sqlite> select * from test limit 1,2;
等價於> select * from test limit 2 offset 1;
都表示從偏移量為1(即第二行)開始,選取兩行。

mysql/sqlite>select * from test limit 3; #從偏移量為0(這里沒指定,使用默認值)選取三行
除了上面的部分,書中還有兩個重要的部分,連接查詢和集合查詢,在注入中也經常用到。這也是關系代數中的部分,在關系代數中把概念搞清,理解起來很簡單。
先看下連接查詢:
上面介紹from子句時,涉及到兩個表時,結果是兩個表元組的廣義笛卡爾積,這樣的查詢時無意義的。所以要使用連接運算。書中給出連接概念是從兩個關系的笛卡爾積中選取屬性間滿足一定條件的元組。
這里主要探討msyql和sqlite對連接的實現語法。
內連接:from <表1> [inner] join <表2> on|where <屬性間表達式>
也可以使用書中的語法 from <表1>,<表2> where <屬性間表達式>

外連接:mysql 支持 left,right,full外連接,sqlite只支持left外連接
語法: from <表1> <left | right | full> [outer] join <表2> on <屬性間表達式>
mysql中外連接只能用on添加屬性間表達式(mysql使用外連接時where必須在on后面),而sqlite中也可以使用where。
使用連接時最好用on來添加表屬性之間的表達式,where用來添加各個表單獨滿足的屬性表達式。
連接部分就這些,再看下集合查詢:對多個select語句的結果進行集合操作。有交,並,差,就是數學中對集合操作。
集合操作的前提條件:參加集合運算的各元組的列數必須相同,且對應的數據類型必須相同。
語法: select <列1>[,<列2>...] from <表1> <union | intersect | except > select <列1> [,<列2>...] from <表2>;
注意:mysql中使用集合查詢時,可用null代替任何類型。例如select id,name from test union select null,null;雖然id是int型,name是char型,但這樣也是合法的。這點在注入時可利用來獲得列數。
上篇:數據定義之基本表定義 下篇:數據更新之基本表數據操縱