關(guān)系運(yùn)算包括四種:投影、選擇、連接、除。
成都創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站制作、做網(wǎng)站、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的武寧網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
在任何一種數(shù)據(jù)庫管理系統(tǒng)中(包括MySQL),投影對(duì)應(yīng)于SELECT子句,選擇對(duì)應(yīng)于WHERE子句,連接對(duì)應(yīng)于JOIN子句,但除沒有直接的對(duì)應(yīng)語句,需要根據(jù)題目的實(shí)際含義書寫復(fù)雜的SQL,通常都會(huì)包含子查詢。
MySQL是一個(gè)關(guān)系型數(shù)據(jù)庫管理系統(tǒng),由瑞典MySQL AB 公司開發(fā),目前屬于 Oracle 旗下產(chǎn)品。MySQL 是最流行的關(guān)系型數(shù)據(jù)庫管理系統(tǒng)之一,在 WEB 應(yīng)用方面,MySQL是最好的 RDBMS (Relational Database Management System,關(guān)系數(shù)據(jù)庫管理系統(tǒng)) 應(yīng)用軟件。
MySQL是一種關(guān)系數(shù)據(jù)庫管理系統(tǒng),關(guān)系數(shù)據(jù)庫將數(shù)據(jù)保存在不同的表中,而不是將所有數(shù)據(jù)放在一個(gè)大倉庫內(nèi),這樣就增加了速度并提高了靈活性。
MySQL所使用的 SQL 語言是用于訪問數(shù)據(jù)庫的最常用標(biāo)準(zhǔn)化語言。MySQL 軟件采用了雙授權(quán)政策,分為社區(qū)版和商業(yè)版,由于其體積小、速度快、總體擁有成本低,尤其是開放源碼這一特點(diǎn),一般中小型網(wǎng)站的開發(fā)都選擇 MySQL 作為網(wǎng)站數(shù)據(jù)庫。
由于其社區(qū)版的性能卓越,搭配 PHP 和 Apache 可組成良好的開發(fā)環(huán)境。
由于MySQL是開放源碼軟件,對(duì)于一般的個(gè)人使用者和中小型企業(yè)來說,MySQL提供的功能綽綽有余,可以大大降低開發(fā)成本。
Linux作為操作系統(tǒng),Apache 或Nginx作為 Web 服務(wù)器,MySQL 作為數(shù)據(jù)庫,PHP/Perl/Python作為服務(wù)器端腳本解釋器。由于這四個(gè)軟件都是免費(fèi)或開放源碼軟件(FLOSS),因此使用這種方式不用花一分錢(除開人工成本)就可以建立起一個(gè)穩(wěn)定、免費(fèi)的網(wǎng)站系統(tǒng),被業(yè)界稱為“LAMP“或“LNMP”組合。
掌握SQL四條最基本的數(shù)據(jù)操作語句:Insert,Select,Update和Delete。
練掌握SQL是數(shù)據(jù)庫用戶的寶貴財(cái) 富。在本文中,我們將引導(dǎo)你掌握四條最基本的數(shù)據(jù)操作語句—SQL的核心功能—來依次介紹比較操作符、選擇斷言以及三值邏輯。當(dāng)你完成這些學(xué)習(xí)后,顯然你已經(jīng)開始算是精通SQL了。
在我們開始之前,先使用CREATE TABLE語句來創(chuàng)建一個(gè)表(如圖1所示)。DDL語句對(duì)數(shù)據(jù)庫對(duì)象如表、列和視進(jìn)行定義。它們并不對(duì)表中的行進(jìn)行處理,這是因?yàn)镈DL語句并不處理數(shù)據(jù)庫中實(shí)際的數(shù)據(jù)。這些工作由另一類SQL語句—數(shù)據(jù)操作語言(DML)語句進(jìn)行處理。
SQL中有四種基本的DML操作:INSERT,SELECT,UPDATE和DELETE。由于這是大多數(shù)SQL用戶經(jīng)常用到的,我們有必要在此對(duì)它們進(jìn)行一一說明。在圖1中我們給出了一個(gè)名為EMPLOYEES的表。其中的每一行對(duì)應(yīng)一個(gè)特定的雇員記錄。請(qǐng)熟悉這張表,我們?cè)诤竺娴睦又袑⒁玫剿?/p>
INSERT語句
用戶可以用INSERT語句將一行記錄插入到指定的一個(gè)表中。例如,要將雇員John Smith的記錄插入到本例的表中,可以使用如下語句:
INSERT INTO EMPLOYEES VALUES
('Smith','John','1980-06-10',
'Los Angles',16,45000);
通過這樣的INSERT語句,系統(tǒng)將試著將這些值填入到相應(yīng)的列中。這些列按照我們創(chuàng)建表時(shí)定義的順序排列。在本例中,第一個(gè)值“Smith”將填到第一個(gè)列LAST_NAME中;第二個(gè)值“John”將填到第二列FIRST_NAME中……以此類推。
我們說過系統(tǒng)會(huì)“試著”將值填入,除了執(zhí)行規(guī)則之外它還要進(jìn)行類型檢查。如果類型不符(如將一個(gè)字符串填入到類型為數(shù)字的列中),系統(tǒng)將拒絕這一次操作并返回一個(gè)錯(cuò)誤信息。
如果SQL拒絕了你所填入的一列值,語句中其他各列的值也不會(huì)填入。這是因?yàn)镾QL提供對(duì)事務(wù)的支持。一次事務(wù)將數(shù)據(jù)庫從一種一致性轉(zhuǎn)移到另一種一致性。如果事務(wù)的某一部分失敗,則整個(gè)事務(wù)都會(huì)失敗,系統(tǒng)將會(huì)被恢復(fù)(或稱之為回退)到此事務(wù)之前的狀態(tài)。
回到原來的INSERT的例子,請(qǐng)注意所有的整形十進(jìn)制數(shù)都不需要用單引號(hào)引起來,而字符串和日期類型的值都要用單引號(hào)來區(qū)別。為了增加可讀性而在數(shù)字間插入逗號(hào)將會(huì)引起錯(cuò)誤。記住,在SQL中逗號(hào)是元素的分隔符。
同樣要注意輸入文字值時(shí)要使用單引號(hào)。雙引號(hào)用來封裝限界標(biāo)識(shí)符。
對(duì)于日期類型,我們必須使用SQL標(biāo)準(zhǔn)日期格式(yyyy-mm-dd),但是在系統(tǒng)中可以進(jìn)行定義,以接受其他的格式。當(dāng)然,2000年臨近,請(qǐng)你最好還是使用四位來表示年份。
既然你已經(jīng)理解了INSERT語句是怎樣工作的了,讓我們轉(zhuǎn)到EMPLOYEES表中的其他部分:
INSERT INTO EMPLOYEES VALUES
('Bunyan','Paul','1970-07-04',
'Boston',12,70000);
INSERT INTO EMPLOYEES VALUES
('John','Adams','1992-01-21',
'Boston',20,100000);
INSERT INTO EMPLOYEES VALUES
('Smith','Pocahontas','1976-04-06',
'Los Angles',12,100000);
INSERT INTO EMPLOYEES VALUES
('Smith','Bessie','1940-05-02',
'Boston',5,200000);
INSERT INTO EMPLOYEES VALUES
('Jones','Davy','1970-10-10',
'Boston',8,45000);
INSERT INTO EMPLOYEES VALUES
('Jones','Indiana','1992-02-01',
'Chicago',NULL,NULL);
在最后一項(xiàng)中,我們不知道Jones先生的工薪級(jí)別和年薪,所以我們輸入NULL(不要引號(hào))。NULL是SQL中的一種特殊情況,我們以后將進(jìn)行詳細(xì)的討論?,F(xiàn)在我們只需認(rèn)為NULL表示一種未知的值。
有時(shí),像我們剛才所討論的情況,我們可能希望對(duì)某一些而不是全部的列進(jìn)行賦值。除了對(duì)要省略的列輸入NULL外,還可以采用另外一種INSERT語句,如下:
INSERT INTO EMPLOYEES(
FIRST_NAME, LAST_NAME,
HIRE_DATE, BRANCH_OFFICE)
VALUE(
'Indiana','Jones',
'1992-02-01','Indianapolis');
這樣,我們先在表名之后列出一系列列名。未列出的列中將自動(dòng)填入缺省值,如果沒有設(shè)置缺省值則填入NULL。請(qǐng)注意我們改變了列的順序,而值的順序要對(duì)應(yīng)新的列的順序。如果該語句中省略了FIRST_NAME和LAST_NAME項(xiàng)(這兩項(xiàng)規(guī)定不能為空),SQL操作將失敗。
讓我們來看一看上述INSERT語句的語法圖:
INSERT INTO table
[(column { ,column})]
VALUES
(columnvalue [{,columnvalue}]);
和前一篇文章中一樣,我們用方括號(hào)來表示可選項(xiàng),大括號(hào)表示可以重復(fù)任意次數(shù)的項(xiàng)(不能在實(shí)際的SQL語句中使用這些特殊字符)。VALUE子句和可選的列名列表中必須使用圓括號(hào)。
SELECT語句
SELECT語句可以從一個(gè)或多個(gè)表中選取特定的行和列。因?yàn)椴樵兒蜋z索數(shù)據(jù)是數(shù)據(jù)庫管理中最重要的功能,所以SELECT語句在SQL中是工作量最大的部分。實(shí)際上,僅僅是訪問數(shù)據(jù)庫來分析數(shù)據(jù)并生成報(bào)表的人可以對(duì)其他SQL語句一竅不通。
SELECT語句的結(jié)果通常是生成另外一個(gè)表。在執(zhí)行過程中系統(tǒng)根據(jù)用戶的標(biāo)準(zhǔn)從數(shù)據(jù)庫中選出匹配的行和列,并將結(jié)果放到臨時(shí)的表中。在直接SQL(direct SQL)中,它將結(jié)果顯示在終端的顯示屏上,或者將結(jié)果送到打印機(jī)或文件中。也可以結(jié)合其他SQL語句來將結(jié)果放到一個(gè)已知名稱的表中。
SELECT語句功能強(qiáng)大。雖然表面上看來它只用來完成本文第一部分中提到的關(guān)系代數(shù)運(yùn)算“選擇”(或稱“限制”),但實(shí)際上它也可以完成其他兩種關(guān)系運(yùn)算—“投影”和“連接”,SELECT語句還可以完成聚合計(jì)算并對(duì)數(shù)據(jù)進(jìn)行排序。
SELECT語句最簡(jiǎn)單的語法如下:
SELECT columns FROM tables;
當(dāng)我們以這種形式執(zhí)行一條SELECT語句時(shí),系統(tǒng)返回由所選擇的列以及用戶選擇的表中所有指定的行組成的一個(gè)結(jié)果表。這就是實(shí)現(xiàn)關(guān)系投影運(yùn)算的一個(gè)形式。
讓我們看一下使用圖1中EMPLOYEES表的一些例子(這個(gè)表是我們以后所有SELECT語句實(shí)例都要使用的。而我們?cè)趫D2和圖3中給出了查詢的實(shí)際結(jié)果。我們將在其他的例子中使用這些結(jié)果)。
假設(shè)你想查看雇員工作部門的列表。那下面就是你所需要編寫的SQL查詢:
SELECT BRANCH_OFFICE FROM EMPLOYEES;
以上SELECT語句的執(zhí)行將產(chǎn)生如圖2中表2所示的結(jié)果。
由于我們?cè)赟ELECT語句中只指定了一個(gè)列,所以我們的結(jié)果表中也只有一個(gè)列。注意結(jié)果表中具有重復(fù)的行,這是因?yàn)橛卸鄠€(gè)雇員在同一部門工作(記住SQL從所選的所有行中將值返回)。要消除結(jié)果中的重復(fù)行,只要在SELECT語句中加上DISTINCT子句:
SELECT DISTINCT BRANCH_OFFICE
FROM EMPLOYEES;
這次查詢的結(jié)果如表3所示。
現(xiàn)在已經(jīng)消除了重復(fù)的行,但結(jié)果并不是按照順序排列的。如果你希望以字母表順序?qū)⒔Y(jié)果列出又該怎么做呢?只要使用ORDER BY子句就可以按照升序或降序來排列結(jié)果:
SELECT DISTINCT BRANCH_OFFICE
FROM EMPLOYEES
ORDER BY BRANCH_OFFICE ASC;
這一查詢的結(jié)果如表4所示。請(qǐng)注意在ORDER BY之后是如何放置列名BRANCH _OFFICE的,這就是我們想要對(duì)其進(jìn)行排序的列。為什么即使是結(jié)果表中只有一個(gè)列時(shí)我們也必須指出列名呢?這是因?yàn)槲覀冞€能夠按照表中其他列進(jìn)行排序,即使它們并不顯示出來。列名BRANCH_ OFFICE之后的關(guān)鍵字ASC表示按照升序排列。如果你希望以降序排列,那么可以用關(guān)鍵字DESC。
同樣我們應(yīng)該指出ORDER BY子句只將臨時(shí)表中的結(jié)果進(jìn)行排序;并不影響原來的表。
假設(shè)我們希望得到按部門排序并從工資最高的雇員到工資最低的雇員排列的列表。除了工資括號(hào)中的內(nèi)容,我們還希望看到按照聘用時(shí)間從最近聘用的雇員開始列出的列表。以下是你將要用到的語句:
SELECT BRANCH_OFFICE,FIRST_NAME,
LAST_NAME,SALARY,HIRE_DATE
FROM EMPLOYEES
ORDER BY SALARY DESC,
HIRE_DATE DESC;
這里我們進(jìn)行了多列的選擇和排序。排序的優(yōu)先級(jí)由語句中的列名順序所決定。SQL將先對(duì)列出的第一個(gè)列進(jìn)行排序。如果在第一個(gè)列中出現(xiàn)了重復(fù)的行時(shí),這些行將被按照第二列進(jìn)行排序,如果在第二列中又出現(xiàn)了重復(fù)的行時(shí),這些行又將被按照第三列進(jìn)行排序……如此類推。這次查詢的結(jié)果如表5所示。
將一個(gè)很長(zhǎng)的表中的所有列名寫出來是一件相當(dāng)麻煩的事,所以SQL允許在選擇表中所有的列時(shí)使用*號(hào):
SELECT * FROM EMPLOYEES;
這次查詢返回整個(gè)EMPLOYEES表,如表1所示。
下面我們對(duì)開始時(shí)給出的SELECT語句的語法進(jìn)行一下更新(豎直線表示一個(gè)可選項(xiàng),允許在其中選擇一項(xiàng)。):
SELECT [DISTINCT]
(column [{, columns}])| *
FROM table [ {, table}]
[ORDER BY column [ASC] | DESC
[ {, column [ASC] | DESC }]];
定義選擇標(biāo)準(zhǔn)
在我們目前所介紹的SELECT語句中,我們對(duì)結(jié)果表中的列作出了選擇但返回的是表中所有的行。讓我們看一下如何對(duì)SELECT語句進(jìn)行限制使得它只返回希望得到的行:
SELECT columns FROM tables [WHERE predicates];
WHERE子句對(duì)條件進(jìn)行了設(shè)置,只有滿足條件的行才被包括到結(jié)果表中。這些條件由斷言(predicate)進(jìn)行指定(斷言指出了關(guān)于某件事情的一種可能的事實(shí))。如果該斷言對(duì)于某個(gè)給定的行成立,該行將被包括到結(jié)果表中,否則該行被忽略。在SQL語句中斷言通常通過比較來表示。例如,假如你需要查詢所有姓為Jones的職員,則可以使用以下SELECT語句:
SELECT * FROM EMPLOYEES
WHERE LAST_NAME = 'Jones';
LAST_NAME = 'Jones'部分就是斷言。在執(zhí)行該語句時(shí),SQL將每一行的LAST_NAME列與“Jones”進(jìn)行比較。如果某一職員的姓為“Jones”,即斷言成立,該職員的信息將被包括到結(jié)果表中(見表6)。
使用最多的六種比較
我們上例中的斷言包括一種基于“等值”的比較(LAST_NAME = 'Jones'),但是SQL斷言還可以包含其他幾種類型的比較。其中最常用的為:
等于 =
不等于
小于
大于
小于或等于 =
大于或等于 =
下面給出了不是基于等值比較的一個(gè)例子:
SELECT * FROM EMPLOYEES
WHERE SALARY 50000;
沒在mysql中試過,不過最近在使用集算器,可以給樓主做下參考。
首先,不是所有的數(shù)據(jù)庫都提供 pivot;其次,就算所有的數(shù)據(jù)庫都提供 pivot,但如果是匯總了多個(gè)數(shù)據(jù)庫的數(shù)據(jù)后還想再來個(gè) pivot?那還是要用到集算器的 pivot。
下面我們來看集算器的 pivot 如何使用
代碼說明:
A1:第一步連接數(shù)據(jù)庫
A2:第二步提取數(shù)據(jù)做預(yù)處理 (這一步可進(jìn)一步擴(kuò)展為做匯總或聚合等復(fù)雜的計(jì)算,具體方法請(qǐng)參考相關(guān)文章)
A3:第三步即實(shí)現(xiàn) pivot 的列轉(zhuǎn)行功能并呈現(xiàn)出來
Mysql?工作原理圖
Mysql是由SQL接口,解析器,優(yōu)化器,緩存,存儲(chǔ)引擎組成的。
mysql原理圖各個(gè)組件說明:
1. connectors
與其他編程語言中的sql?語句進(jìn)行交互,如php、java等。
2. Management Serveices Utilities
系統(tǒng)管理和控制工具
3. Connection Pool (連接池)
管理緩沖用戶連接,線程處理等需要緩存的需求
4. SQL Interface (SQL接口)
接受用戶的SQL命令,并且返回用戶需要查詢的結(jié)果。比如select from就是調(diào)用SQL Interface
5. Parser?(解析器)
SQL命令傳遞到解析器的時(shí)候會(huì)被解析器驗(yàn)證和解析。
主要功能:
a .?將SQL語句分解成數(shù)據(jù)結(jié)構(gòu),并將這個(gè)結(jié)構(gòu)傳遞到后續(xù)步驟,后面SQL語句的傳遞和處理就是基于這個(gè)結(jié)構(gòu)的
b. ?如果在分解構(gòu)成中遇到錯(cuò)誤,那么就說明這個(gè)sql語句是不合理的,語句將不會(huì)繼續(xù)執(zhí)行下去
6. Optimizer (查詢優(yōu)化器)
SQL語句在查詢之前會(huì)使用查詢優(yōu)化器對(duì)查詢進(jìn)行優(yōu)化(產(chǎn)生多種執(zhí)行計(jì)劃,最終數(shù)據(jù)庫會(huì)選擇最優(yōu)化的方案去執(zhí)行,盡快返會(huì)結(jié)果)?他使用的是“選取-投影-聯(lián)接”策略進(jìn)行查詢。
用一個(gè)例子就可以理解:?select uid,name from user where gender = 1;
這個(gè)select?查詢先根據(jù)where?語句進(jìn)行選取,而不是先將表全部查詢出來以后再進(jìn)行g(shù)ender過濾
這個(gè)select查詢先根據(jù)uid和name進(jìn)行屬性投影,而不是將屬性全部取出以后再進(jìn)行過濾
將這兩個(gè)查詢條件聯(lián)接起來生成最終查詢結(jié)果.
7. Cache和Buffer (查詢緩存)
如果查詢緩存有命中的查詢結(jié)果,查詢語句就可以直接去查詢緩存中取數(shù)據(jù)。
這個(gè)緩存機(jī)制是由一系列小緩存組成的。比如表緩存,記錄緩存,key緩存,權(quán)限緩存等
8.Engine (存儲(chǔ)引擎)
存儲(chǔ)引擎是MySql中具體的與文件打交道的子系統(tǒng)。也是Mysql最具有特色的一個(gè)地方。
Mysql的存儲(chǔ)引擎是插件式的。它根據(jù)MySql AB公司提供的文件訪問層的一個(gè)抽象接口來定制一種文件訪問機(jī)制(這種訪問機(jī)制就叫存儲(chǔ)引擎)
SQL?語句執(zhí)行過程
數(shù)據(jù)庫通常不會(huì)被直接使用,而是由其他編程語言通過SQL語句調(diào)用mysql,由mysql處理并返回執(zhí)行結(jié)果。那么Mysql接受到SQL語句后,又是如何處理
首先程序的請(qǐng)求會(huì)通過mysql的connectors與其進(jìn)行交互,請(qǐng)求到處后,會(huì)暫時(shí)存放在連接池(connection pool)中并由處理器(Management Serveices Utilities)管理。當(dāng)該請(qǐng)求從等待隊(duì)列進(jìn)入到處理隊(duì)列,管理器會(huì)將該請(qǐng)求丟給SQL接口(SQL Interface)。SQL接口接收到請(qǐng)求后,它會(huì)將請(qǐng)求進(jìn)行hash處理并與緩存中的結(jié)果進(jìn)行對(duì)比,如果完全匹配則通過緩存直接返回處理結(jié)果;否則,需要完整的走一趟流程:
(1)由SQL接口丟給后面的解釋器(Parser),解釋器會(huì)判斷SQL語句正確與否,若正確則將其轉(zhuǎn)化為數(shù)據(jù)結(jié)構(gòu)。
(2)解釋器處理完,便來到后面的優(yōu)化器(Optimizer),它會(huì)產(chǎn)生多種執(zhí)行計(jì)劃,最終數(shù)據(jù)庫會(huì)選擇最優(yōu)化的方案去執(zhí)行,盡快返會(huì)結(jié)果。
(3)確定最優(yōu)執(zhí)行計(jì)劃后,SQL語句此時(shí)便可以交由存儲(chǔ)引擎(Engine)處理,存儲(chǔ)引擎將會(huì)到后端的存儲(chǔ)設(shè)備中取得相應(yīng)的數(shù)據(jù),并原路返回給程序。
注意點(diǎn)
(1)如何緩存查詢數(shù)據(jù)
存儲(chǔ)引擎處理完數(shù)據(jù),并將其返回給程序的同時(shí),它還會(huì)將一份數(shù)據(jù)保留在緩存中,以便更快速的處理下一次相同的請(qǐng)求。具體情況是,mysql會(huì)將查詢的語句、執(zhí)行結(jié)果等進(jìn)行hash,并保留在cache中,等待下次查詢。
(2)buffer與cache的區(qū)別
從mysql原理圖可以看到,緩存那里實(shí)際上有buffer和cache兩個(gè),那它們之間的區(qū)別:簡(jiǎn)單的說就是,buffer是寫緩存,cache是讀緩存。
(3)如何判斷緩存中是否已緩存需要的數(shù)據(jù)
這里可能有一個(gè)誤區(qū),覺得處理SQL語句的時(shí)候,為了判斷是否已緩存查詢結(jié)果,會(huì)將整個(gè)流程走一遍,取得執(zhí)行結(jié)果后再與需要的進(jìn)行對(duì)比,看看是否命中,并以此說,既然不管緩存中有沒有緩存到查詢內(nèi)容,都要整個(gè)流程走一遍,那緩存的優(yōu)勢(shì)在哪?
其實(shí)并不是這樣,在第一次查詢后,mysql便將查詢語句以及查詢結(jié)果進(jìn)行hash處理并保留在緩存中,SQL查詢到達(dá)之后,對(duì)其進(jìn)行同樣的hash處理后,將兩個(gè)hash值進(jìn)行對(duì)照,如果一樣,則命中,從緩存中返回查詢結(jié)果;否則,需要整個(gè)流程走一遍。