者:青石路
cnblogs.com/youzhibing/p/11516154.html
標準 SQL 規定,在對表進行聚合查詢的時候,只能在 SELECT 子句中寫下面 3 種內容:通過 GROUP BY 子句指定的聚合鍵、聚合函數(SUM 、AVG 等)、常量。我們來看個例子:
我們有 學生班級表(tbl_student_class) 以及 數據如下 :
我們想統計各個班(班級號、班級名)一個有多少人、以及最大的學號,我們該怎么寫這個查詢 SQL ?我想大家應該都會
SELECT cno,cname,count(sno),MAX(sno)
FROM tbl_student_class
GROUP BY cno,cname;
可是有人會想了,cno 和 cname 本來就是一對一,cno 一旦確定,cname 也就確定了,那 SQL 是不是可以這么寫 ?
SELECT cno,cname,count(sno),MAX(sno)
FROM tbl_student_class
GROUP BY cno;
執行報錯了:
[Err] 1055 - Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.tbl_student_class.cname' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
提示信息:SELECT 列表中的第二個表達式(cname)不在 GROUP BY 的子句中,同時它也不是聚合函數;這與 sql 模式:ONLY_FULL_GROUP_BY 不相容。
為什么 GROUP BY 之后不能直接引用原表(不在 GROUP BY 子句)中的列 ?莫急,我們慢慢往下看。
MySQL 服務器可以在不同的 SQL 模式下運行,并且可以針對不同的客戶端以不同的方式應用這些模式,具體取決于 sql_mode 系統變量的值。DBA 可以設置全局SQL模式以匹配站點服務器操作要求,并且每個應用程序可以將其會話 SQL 模式設置為其自己的要求。
模式會影響 MySQL 支持的 SQL 語法以及它執行的 數據驗證檢查,這使得在不同環境中使用MySQL以及將MySQL與其他數據庫服務器一起使用變得更加容易。更多詳情請查閱官網:Server SQL Modes。
MySQL 版本不同,內容會略有不同(包括默認值),查閱的時候注意與自身的 MySQL 版本保持一致。
SQL 模式主要分兩類:語法支持類和數據檢查類,常用的如下
對于 GROUP BY 聚合操作,如果在 SELECT 中的列、HAVING 或者 ORDER BY 子句的列,沒有在GROUP BY中出現,那么這個SQL是不合法的
啟用 ANSI_QUOTES 后,不能用雙引號來引用字符串,因為它被解釋為識別符,作用與 ` 一樣。設置它以后,update t set f1="" …,會報 Unknown column ‘’ in field list 這樣的語法錯誤
將 || 視為字符串的連接操作符而非 或 運算符,這和Oracle數據庫是一樣的,也和字符串的拼接函數 CONCAT() 相類似
使用 SHOW CREATE TABLE 時不會輸出MySQL特有的語法部分,如 ENGINE ,這個在使用 mysqldump 跨DB種類遷移的時候需要考慮
字面意思不自動創建用戶。在給MySQL用戶授權時,我們習慣使用 GRANT … ON … TO dbuser 順道一起創建用戶。設置該選項后就與oracle操作類似,授權之前必須先建立用戶
認為日期 ‘0000-00-00’ 非法,與是否設置后面的嚴格模式有關
1、如果設置了嚴格模式,則 NO_ZERO_DATE 自然滿足。但如果是 INSERT IGNORE 或 UPDATE IGNORE,’0000-00-00’依然允許且只顯示warning;
2、如果在非嚴格模式下,設置了NO_ZERO_DATE,效果與上面一樣,’0000-00-00’ 允許但顯示warning;如果沒有設置NO_ZERO_DATE,no warning,當做完全合法的值;
3、NO_ZERO_IN_DATE情況與上面類似,不同的是控制日期和天,是否可為 0 ,即 2010-01-00 是否合法;
使用 ALTER TABLE 或 CREATE TABLE 指定 ENGINE 時, 需要的存儲引擎被禁用或未編譯,該如何處理。啟用 NO_ENGINE_SUBSTITUTION 時,那么直接拋出錯誤;不設置此值時,CREATE用默認的存儲引擎替代,ATLER不進行更改,并拋出一個 warning
設置它,表示啟用嚴格模式。注意 STRICT_TRANS_TABLES 不是幾種策略的組合,單獨指 INSERT、UPDATE 出現少值或無效值該如何處理:
1、前面提到的把 ‘’ 傳給int,嚴格模式下非法,若啟用非嚴格模式則變成 0,產生一個warning;
2、Out Of Range,變成插入最大邊界值;
3、當要插入的新行中,不包含其定義中沒有顯式DEFAULT子句的非NULL列的值時,該列缺少值;
當我們沒有修改配置文件的情況下,MySQL 是有自己的默認模式的;版本不同,默認模式也不同
-- 查看 MySQL 版本
SELECT VERSION();
-- 查看 sql_mode
SELECT @@sql_mode;
我們可以看到,5.7.21 的默認模式包含:
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
而第一個:ONLY_FULL_GROUP_BY 就會約束:當我們進行聚合查詢的時候,SELECT 的列不能直接包含非 GROUP BY 子句中的列。那如果我們去掉該模式(從“嚴格模式”到“寬松模式”)呢 ?
我們發現,上述報錯的 SQL
-- 寬松模式下 可以執行
SELECT cno,cname,count(sno),MAX(sno)
FROM tbl_student_class
GROUP BY cno;
能正常執行了,但是一般情況下不推薦這樣配置,線上環境往往是“嚴格模式”,而不是“寬松模式”;雖然案例中,無論是“嚴格模式”,還是“寬松模式”,結果都是對的,那是因為 cno 與 cname 唯一對應的,如果 cno 與 cname 不是唯一對應,那么在“寬松模式下” cname 的值是隨機的,這就會造成難以排查的問題,有興趣的可以去試試。那為什么會有 ONLY_FULL_GROUP_BY 模式呢 ? 我們繼續往下看
階(order)是用來區分集合或謂詞的階數的概念。謂詞邏輯中,根據輸入值的階數對謂詞進行分類。
=或者 BETWEEEN 等輸入值為一行的謂詞叫作"一階謂詞",而像 EXISTS 這樣輸入值為行的集合的謂詞叫作"二階謂詞"(HAVING 的輸入值也是集合,但它不是謂詞)。以此類推,三階謂詞=輸入值為"集合的集合"的謂詞,四階謂詞=輸入值為"集合的集合的集合"的謂詞,但是 SQL 里并不會出現三階以上的情況,所以不用太在意。
簡單點如下圖
談到了階,就不得不談下集合論;集合論是 SQL 語言的根基,因為它的這個特性,SQL 也被稱為面向集合語言。只有從集合的角度來思考,才能明白 SQL 的強大威力。通過上圖,相信大家也都能看到,這里不做更深入的講解了,有興趣的可以去查相關資料。
很多人都知道聚合查詢的限制,但是很少有人能正確地理解為什么會有這樣的約束。表 tbl_student_class 中的 cname 存儲的是每位學生的班級信息。
但需要注意的是,這里的 cname 只是每個學生的屬性,并不是小組的屬性,而 GROUP BY 又是聚合操作,操作的對象就是由多個學生組成的小組,因此,小組的屬性只能是平均或者總和等統計性質的屬性,如下圖
詢問每個學生的 cname 是可以的,但是詢問由多個學生組成的小組的 cname 就沒有意義了。對于小組來說,只有"一共多少學生"或者"最大學號是多少?"這樣的問法才是有意義的。
強行將適用于個體的屬性套用于團體之上,純粹是一種分類錯誤;而 GROUP BY 的作用是將一個個元素劃分成若干個子集,使用 GROUP BY 聚合之后,SQL 的操作對象便由 0 階的"行"變為了 1 階的"行的集合",此時,行的屬性便不能使用了。
SQL 的世界其實是層級分明的等級社會,將低階概念的屬性用在高階概念上會導致秩序的混亂,這是不允許的。此時我相信大家都明白:為什么聚合后不能再引用原表中的列 。
現在的集合論認為單元素集合是一種正常的集合。單元素集合和空集一樣,主要是為了保持理論的完整性而定義的。因此對于以集合論為基礎的 SQL 來說,當然也需要嚴格地區分元素和單元素集合。因此,元素 a 和集合 {a} 之間存在著非常醒目的層級差別。
a ≠ {a}
這兩個層級的區別分別對應著 SQL 中的 WHERE 子句和 HAVING 子句的區別。WHERE 子句用于處理"行"這種 0 階的對象,而 HAVING 子句用來處理"集合"這種 1 階的對象。
1、SQL 嚴格區分層級,包括謂詞邏輯中的層級(EXISTS),也包括集合論中的層級(GROUP BY);
2、有了層級區分,那么適用于個體上的屬性就不適用于團體了,這也就是為什么聚合查詢的 SELECT 子句中不能直接引用原表中的列的原因;
3、一般來說,單元素集合的屬性和其唯一元素的屬性是一樣的。這種只包含一個元素的集合讓人覺得似乎沒有必要特意地當成集合來看待,但是為了保持理論的完整性,我們還是要嚴格區分元素和單元素集合;
例
帶有 <thead>、<tfoot> 和 <tbody> 元素的 HTML 表格:
<table border="1">
<thead>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
</thead>
<tfoot>
<tr>
<td>Sum</td>
<td>0</td>
</tr>
</tfoot>
<tbody>
<tr>
<td>January</td>
<td>0</td>
</tr>
<tr>
<td>February</td>
<td></td>
</tr>
</tbody>
</table>
瀏覽器支持
所有主流瀏覽器都支持 <thead> 標簽。
標簽定義及使用說明
<thead> 標簽用于組合 HTML 表格的表頭內容。
<thead> 元素應該與 <tbody> 和 <tfoot> 元素結合起來使用,用來規定表格的各個部分(表頭、主體、頁腳)。
通過使用這些元素,使瀏覽器有能力支持獨立于表格表頭和表格頁腳的表格主體滾動。當包含多個頁面的長的表格被打印時,表格的表頭和頁腳可被打印在包含表格數據的每張頁面上。
<thead> 標簽必須被用在以下情境中:作為 <table> 元素的子元素,出現在 <caption>、<colgroup> 元素之后,<tbody>、 <tfoot> 和 <tr> 元素之前。
提示和注釋
注釋:<thead> 元素內部必須包含一個或者多個 <tr> 標簽。
提示:<thead>、<tbody> 和 <tfoot> 元素默認不會影響表格的布局。不過,您可以使用 CSS 來為這些元素定義樣式,從而改變表格的外觀。
HTML 4.01 與 HTML5之間的差異
在 HTML 5 中,不再支持 HTML 4.01 中 <thead> 標簽的任何屬性。
屬性
屬性 | 值 | 描述 |
---|---|---|
align | rightleftcenterjustifychar | HTML5 不支持。定義 <thead> 元素中內容的對齊方式。 |
char | character | HTML5 不支持。規定 <thead> 元素中內容根據哪個字符來對進行文本對齊。 |
charoff | number | HTML5 不支持。規定 <thead> 元素中內容的第一個對齊字符的偏移量。 |
valign | topmiddlebottombaseline | HTML5 不支持。規定 <thead> 元素中內容的垂直對齊方式。 |
全局屬性
<thead> 標簽支持 HTML 的全局屬性。
事件屬性
<thead> 標簽支持 HTML 的事件屬性。
如您還有不明白的可以在下面與我留言或是與我探討QQ群308855039,我們一起飛!
這篇文章中,我將分享21個HTML技巧,包括代碼片段,可以提升你的編碼技能。
讓我們立即開始吧。
(本文視頻講解:java567.com)
*請認真填寫需求信息,我們會在24小時內與您取得聯系。