計算機誕生后,數據開始在計算機中存儲并計算,并設計出了數據庫系統,數據庫系統解決的問題:持久化存儲,優化讀寫,保證數據的有效性。
當前使用的數據庫,主要分為兩類
1、文檔型,如sqlite,就是一個文件,通過對文件的復制完成數據庫的復制;
2、服務型,如mysql、oracle、postgre,數據存儲在一個物理文件中,但是需要使用終端以tcp/ip協議連接,進行數據庫的讀寫操作。
E-R模型
當前物理的數據庫都是按照E-R模型進行設計的,E表示entity,實體,R表示relationship,關系
ER模型是構建現實世界和程序數據世界的橋梁,通過ER圖可以理清楚程序的業務關系,在工程中只有先把業務關系搞清楚了,才好設計數據庫,才好進行相應的編碼工作。其實在一個大的工程中,設計數據庫和理清業務關系甚至要比實際的編碼時間都要長。
關系描述兩個實體之間的對應規則,包括
1.一對一
合法的情況下:一個男人娶一個女人,一個女人嫁一個男人
2.一對多
目前教室里,一個老師教多個學生,一個學生被一個老師教
一個教室里有很多學生,一個學生只能一個教室
3.多對多
在大學中,一個學生選很多課程,一個課程被學生選
在大學里,一個學生可以有很多老師,一個老師可以教很多學生
關系轉換為數據庫表中的一個列在關系型數據庫中一行就是一個對象
三范式
經過研究和對使用中問題的總結,對于設計數據庫提出了一些規范,這些規范被稱為范式
1.第一范式(1NF):列不可拆分
2.第二范式(2NF):唯一標識
3.第三范式(3NF):引用主鍵
簡而言之:
說明:后一個范式,都是在前一個范式的基礎上建立的。
數據類型
MySQL支持所有標準的SQL數據類型,主要分3類:數值類型、字符串類型、時間日期類型。
1、數值類型
1.1、整數類型
下面一張表就能解釋清楚:
1.2、定點數
DECIMAL和NUMERIC類型在MySQL中視為相同的類型。它們用于保存必須為確切精度的值。
我們看到上面這個例子中有兩個參數,即DECIMAL(M,D),其中M表示十進制數字總的個數,D表示小數點后面數字的位數,上例中的取值范圍為-999.99~999.99。
如果存儲時,整數部分超出了范圍(如上面的例子中,添加數值為1000.01),MySql就會報錯,不允許存這樣的值。
如果存儲時,小數點部分若超出范圍,就分以下情況:
若四舍五入后,整數部分沒有超出范圍,則只警告,但能成功操作并四舍五入刪除多余的小數位后保存。如999.994實際被保存為999.99。
若四舍五入后,整數部分超出范圍,則MySql報錯,并拒絕處理。如999.995和-999.995都會報錯。
M的默認取值為10,D默認取值為0。如果創建表時,某字段定義為decimal類型不帶任何參數,等同于decimal(10,0)。帶一個參數時,D取默認值。
M的取值范圍為1~65,取0時會被設為默認值,超出范圍會報錯。
D的取值范圍為0~30,而且必須<=M,超出范圍會報錯。
所以,很顯然,當M=65,D=0時,可以取得最大和最小值。
1.3、浮點數
浮點數是用來表示實數的一種方法,相對于定點數來說,在長度一定的情況下,具有表示數據范圍大的特點。但同時也存在誤差問題,如果希望保證值比較準確,推薦使用定點數數據類型。
MySql中的浮點類型有float,double和real。他們定義方式為:FLOAT(M,D) 、 REAL(M,D) 、 DOUBLE PRECISION(M,D)。
REAL就是DOUBLE?,如果SQL服務器模式包括REAL_AS_FLOAT選項,REAL是FLOAT的同義詞而不是DOUBLE的同義詞。
“(M,D)”表示該值一共顯示M位整數,其中D位位于小數點后面。例如,定義為FLOAT(7,4)的一個列可以顯示為-999.9999。MySQL保存值時進行四舍五入,因此如果在FLOAT(7,4)列內插入999.00009,近似結果是999.0001。
FLOAT和DOUBLE中的M和D的取值默認都為0,即除了最大最小值,不限制位數。
M取值范圍為0~255。FLOAT只保證6位有效數字的準確性,所以FLOAT(M,D)中,M<=6時,數字通常是準確的。如果M和D都有明確定義,其超出范圍后的處理同decimal。
D取值范圍為0~30,同時必須<=M。double只保證16位有效數字的準確性,所以DOUBLE(M,D)中,M<=16時,數字通常是準確的。如果M和D都有明確定義,其超出范圍后的處理同decimal。
FLOAT和DOUBLE中,若M的定義分別超出7和17,則多出的有效數字部分,取值是不定的,通常數值上會發生錯誤。因為浮點數是不準確的,所以我們要避免使用“=”來判斷兩個數是否相等。
內存中,FLOAT占4-byte(1位符號位 8位表示指數 23位表示尾數),DOUBLE占8-byte(1位符號位 11位表示指數 52位表示尾數)。
1.4、bit(1)
BIT數據類型可用來保存位字段值。BIT(M)類型允許存儲M位值。M范圍為1~64(即64位二進制數),默認為1,BIT其實就是存入二進制的值,類似010110。
如果存入一個BIT類型的值,位數少于M值,則左補0.
如果存入一個BIT類型的值,位數多于M值,MySQL的操作取決于此時有效的SQL模式:
如果模式未設置,MySQL將值裁剪到范圍的相應端點,并保存裁減好的值。
如果模式設置為traditional(“嚴格模式”),超出范圍的值將被拒絕并提示錯誤,并且根據SQL標準插入會失敗。
看下面官方給出的例子:
2、字符串類型
2.1、CHAR和VARCHAR類型
CHAR和VARCHAR類型聲明的長度表示你想要保存的最大字符數。例如,CHAR(30)可以占用30個字符。默認長度都為255。
CHAR列的長度固定為創建表時聲明的長度。長度可以為從0到255的任何值。當保存CHAR值時,在它們的右邊填充空格以達到指定的長度。當檢索到CHAR值時,尾部的空格被刪除掉,所以,我們在存儲時字符串右邊不能有空格,即使有,查詢出來后也會被刪除。在存儲或檢索過程中不進行大小寫轉換。
所以當char類型的字段為唯一值時,添加的值是否已經存在以不包含末尾空格(可能有多個空格)的值確定,比較時會在末尾補滿空格后與現已存在的值比較。
VARCHAR列中的值為可變長字符串。長度可以指定為0到65,535之間的值(實際可指定的最大長度與編碼和其他字段有關,比如,本人MySql使用utf-8編碼格式,大小為標準格式大小的2倍,僅有一個varchar字段時實測最大值僅21844,如果添加一個char(3),則最大取值減少3。整體最大長度是65,532字節)。
同CHAR對比,VARCHAR值保存時只保存需要的字符數,另加一個字節來記錄長度(如果列聲明的長度超過255,則使用兩個字節)。
VARCHAR值保存時不進行填充。當值保存和檢索時尾部的空格仍保留,符合標準SQL。
如果分配給CHAR或VARCHAR列的值超過列的最大長度,則對值進行裁剪以使其適合。如果被裁掉的字符是空格,則會產生一條警告。如果裁剪非空格字符,則會造成錯誤(而不是警告)并通過使用嚴格SQL模式禁用值的插入。
下面顯示了將各種字符串值保存到CHAR(4)和VARCHAR(4)列后的結果:
表中最后一行的值只適用在不使用嚴格模式時;如果MySQL運行使用嚴格模式,超過列長度的值不保存,并且會出現錯誤。因為空格的原因,相同的值存入到長度都足夠的varvhar和char中,取出可能會不同,比如"a"和"a ?"。
2.2、BINARY和VARBINARY類型(2)
BINARY和VARBINARY類型類似于CHAR和VARCHAR類型,但是不同的是,它們存儲的不是字符字符串,而是二進制串。所以它們沒有字符集,并且排序和比較基于列值字節的數值值。
當保存BINARY值時,在它們右邊填充0x00(零字節)值以達到指定長度。取值時不刪除尾部的字節。比較時所有字節很重要(因為空格和0x00是不同的,0x00<空格),包括ORDER BY和DISTINCT操作。比如插入'a '會變成'a \0'。
對于VARBINARY,插入時不填充字符,選擇時不裁剪字節。比較時所有字節很重要。
當類型為BINARY的字段為主鍵時,應考慮上面介紹的存儲方式。
2.3、BLOB和TEXT類型
BLOB是一個二進制大對象,可以容納可變數量的數據。有4種BLOB類型:TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB。它們只是可容納值的最大長度不同。
有4種TEXT類型:TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT。這些對應4種BLOB類型,有相同的最大長度和存儲需求。
BLOB列被視為二進制字符串。TEXT列被視為字符字符串,類似CHAR和BINARY。
在TEXT或BLOB列的存儲或檢索過程中,不存在大小寫轉換。
在大多數方面,可以將BLOB列視為能夠足夠大的VARBINARY列。同樣,可以將TEXT列視為VARCHAR列。
BLOB和TEXT在以下幾個方面不同于VARBINARY和VARCHAR:
1、當保存或檢索BLOB和TEXT列的值時不刪除尾部空格。(這與VARBINARY和VARCHAR列相同)。
2、比較時將用空格對TEXT進行擴充以適合比較的對象,正如CHAR和VARCHAR。
3、對于BLOB和TEXT列的索引,必須指定索引前綴的長度。對于CHAR和VARCHAR,前綴長度是可選的。
4、BLOB和TEXT列不能有默認值。
MySQL Connector/ODBC將BLOB值定義為LONGVARBINARY,將TEXT值定義為LONGVARCHAR。
BLOB或TEXT對象的最大大小由其類型確定,但在客戶端和服務器之間實際可以傳遞的最大值由可用內存數量和通信緩存區大小確定。你可以通過更改max_allowed_packet變量的值更改消息緩存區的大小,但必須同時修改服務器和客戶端程序。
3、時間日期類型
3.1、DATE, DATETIME, 和TIMESTAMP類型
這三者其實是關聯的,都用來表示日期或時間。
當你需要同時包含日期和時間信息的值時則使用DATETIME類型。MySQL以'YYYY-MM-DD HH:MM:SS'格式檢索和顯示DATETIME值。支持的范圍為'1000-01-01 00:00:00'到'9999-12-31 23:59:59'。
當你只需要日期值而不需要時間部分時應使用DATE類型。MySQL用'YYYY-MM-DD'格式檢索和顯示DATE值。支持的范圍是'1000-01-01'到 '9999-12-31'。
TIMESTAMP類型同樣包含日期和時間,范圍從'1970-01-01 00:00:01' UTC 到'2038-01-19 03:14:07' UTC。
3.2、TIME類型
MySQL以'HH:MM:SS'格式檢索和顯示TIME值(或對于大的小時值采用'HHH:MM:SS'格式)。
TIME值的范圍可以從'-838:59:59'到'838:59:59'。小時部分會因此大的原因是TIME類型不僅可以用于表示一天的時間(必須小于24小時),還可能為某個事件過去的時間或兩個事件之間的時間間隔(可以大于24小時,或者甚至為負)。
對于指定為包括時間部分間割符的字符串的TIME值,如果時、分或者秒值小于10,則不需要指定兩位數。'8:3:2'與'08:03:02'相同。
為TIME列分配簡寫值時應注意。沒有冒號,MySQL解釋值時假定最右邊的兩位表示秒。(MySQL解釋TIME值為過去的時間而不是當天的時間)。例如,你可能認為'1112'和1112表示'11:12:00'(11點過12分),但MySQL將它們解釋為'00:11:12'(11分,12 秒)。同樣,'12'和12 被解釋為 '00:00:12'。相反,TIME值中使用冒號則肯定被看作當天的時間。也就是說,'11:12'表示'11:12:00',而不是'00:11:12'。
3.3、YEAR類型
YEAR類型是一個單字節類型用于表示年。MySQL以YYYY格式檢索和顯示YEAR值。范圍是1901到2155。
可以指定各種格式的YEAR值:
1、四位字符串,范圍為'1901'到'2155'。
2、四位數字,范圍為1901到2155。
3、兩位字符串,范圍為'00'到'99'。'00'到'69'和'70'到'99'范圍的值被轉換為2000到2069和1970到1999范圍的YEAR值。
4、兩位整數,范圍為1到99。1到69和70到99范圍的值被轉換為2001到2069和1970到1999范圍的YEAR值。請注意兩位整數范圍與兩位字符串范圍稍有不同,因為你不能直接將零指定為數字并將它解釋為2000。你必須將它指定為一個字符串'0'或'00'或它被解釋為0000。
非法YEAR值被轉換為0000。
約束
1.主鍵primary key
2.非空not null
3.惟一unique
4.默認default
5.外鍵foreign key
基本操作
·創建數據庫:create database 數據庫名 charset=utf8;
·刪除數據庫:drop database數據庫名;
·切換數據庫:use數據庫名;
·查看當前選擇的數據庫:select database();
·查看當前數據庫中所有表:show tables;
·創建表:create table表名(列及類型);? ? ??
主鍵本身是用來唯一標識這一行,沒有業務邏輯意義,所以是什么值不重要,只要唯一就行,所以如果是主鍵不需要修改,auto_increment表示自動增長,只能是數字類型。
如:
create table students(
id int auto_increment primary key,
sname varchar(10) not null
);
·修改表:alter table表名add|modify|drop列名類型;
如:alter table students add birthday datetime;
·刪除表:drop table表名;
·查看表結構:desc表名;
·更改表名稱:rename table原表名to新表名;
·查看表的創建語句:show create table '表名';
·查詢:select * from表名
·增加
全行插入:insert into表名values(...)
缺省插入:insert into表名(列1,...) values(值1,...)
同時插入多條數據:insert into表名values(...),(...)...;
或insert into表名(列1,...) values(值1,...),(值1,...)...;
·主鍵列是自動增長,但是在全列插入時需要占位,通常使用0,插入成功后以實際數據為準
·修改:update 表名 set 列1=值1,... where條件
·刪除:delete?from 表名 where 條件
·邏輯刪除,本質就是修改操作update
alter table students add isdelete bit default 0;
如果需要刪除則
update students isdelete=1 where ...;
備份與恢復
數據備份
·進入超級管理員:sudo -s
·運行mysqldump命令:mysqldump–uroot –p數據庫名> ~/備份文件.sql;
按提示輸入mysql的密碼
數據恢復
·連接mysql,創建數據庫
·退出連接,執行命令:mysql -uroot -p數據庫名< ~/備份文件.sql
根據提示輸入mysql密碼
查詢:
聚合:
分組:分組前面查詢的內容只能是聚合函數和分組
排序:
分頁:
模糊查詢:like(%表示任意多個任意字符,??_表示一個任意字符)
查詢范圍:·in表示在一個非連續的范圍內,between ... and ...表示在一個連續的范圍內。
非空判斷:is null和is not null
去重復:distinct
多表直接查詢其實做的是一個笛卡爾積,可以看到結果并不是我們想要的:
多表查詢:
1、內連接:join或inner join
以上兩種寫法等效,可以看到在DEPT表中,有deptno為40的記錄,但在EMP表中,并沒有員工屬于40這個deptno,在進行內斂查詢時,因為neptno為40無法匹配,所以就自動將其刪除了,所以內連接不會保留無法匹配的記錄。
內連接同樣可以進行一些篩選,有兩種方式的篩選,其效果相同:
2、外聯接:left/right outer join或 left/right join
right表示join右邊的是主表,左邊的是次表,進行外聯接時,主表無法匹配的記錄不會忽略,而會保留,次表中記錄的相應內容會用NULL填充。
自關聯:
舉一個簡單的例子來說明自關聯,假如現在有兩張表結構如下:
觀察兩張表發現,citys表比provinces表多一個列proid,其它列的類型都是一樣的,存儲的都是地區信息,而且每種信息的數據量有限,沒必要增加一個新表,或者將來還要存儲區、鄉鎮信息,都增加新表的開銷太大。因此我們可以把這兩張表合并為一張表。
因為省沒有所屬的省份,所以可以填寫為null
城市所屬的省份pid,填寫省所對應的編號id
這就是自關聯,表中的某一列,關聯了這個表中的另外一列,但是它們的業務邏輯含義是不一樣的,城市信息的pid引用的是省信息的id,在這個表中,結構不變,可以添加區縣、鄉鎮街道、村社區等信息。
子查詢案例:
內置函數:
1、字符串函數:
2、數學函數
3、時間日期函數
視圖
為了引入視圖先看下面一個簡單的查詢操作的例子:
這是一個簡單的查詢命令,相對而言還是稍微有點長的,在工作中,我們遇到的數據庫操作可能比這樣的SQL語句冗長的多,每次重新再寫相同的命令會顯得十分繁瑣,那么能不能像python中的函數那樣把SQL語句封裝起來,每次只需要調用就可以進行多次重復的操作而實現代碼復用呢?視圖就是實現一種類似的功能。視圖本質就是對查詢的一個封裝,虛擬的表,一旦封裝的內容改變了,視圖的內容也隨著用,視圖就是用來進行進行查詢操作的。通過創建視圖,我們可以看到下面的代碼實現了和上述代碼相同的功能,且提高了代碼的復用性。
事務
當一個業務邏輯需要多個sql完成時,如果其中某條sql語句出錯,則希望整個操作都退回,即回到操作前的狀態,保證數據的正確性。使用事務可以完成退回的功能,保證業務邏輯的正確性。
事物有兩個功能:有一個出問題,回滾。都沒有問題,提交。(同生共死)
表的引擎類型必須是innodb或bdb類型,才可以對此表使用事務
事務四大特性(簡稱ACID)
1、原子性(Atomicity):事務中的全部操作在數據庫中是不可分割的,要么全部完成,要么均不執行;
2、一致性(Consistency):幾個并行執行的事務,其執行結果必須與按某一順序串行執行的結果相一致;
3、隔離性(Isolation):事務的執行不受其他事務的干擾,事務執行的中間結果對其他事務必須是透明的;
4、持久性(Durability):對于任意已提交事務,系統必須保證該事務對數據庫的改變不被丟失,即使數據庫出現故障。
事務語句:
開啟begin;
提交commit;
回滾rollback;
例1:
例2:
與python交互
需安裝pip3和pyMySql模塊(針對python3.x版本)
sql語句用法舉例:
1、update main set num=floor(num/10)*10 where num between 20 and 39;
數據庫備份與恢復:
創建數據庫并設置字符集和排序規則:create database 數據庫名 CHARACTER SET utf8 COLLATE utf8_general_ci;
備份整個數據庫:mysqldump 數據庫名> 備份文件名.sql
備份數據庫單張表:mysqldump 數據庫名 表名 > 備份文件名.sql
從整庫備份文件中提取單張表的創建表語句:sed -e'/./{H;$!d;}' -e 'x;/CREATE TABLE `表名`/!d;q' 整庫備份文件名.sql > 提取出來的sql文件名.sql
從整庫備份文件中提取單張表的插入數據sql語句:grep -i 'INSERT INTO `表名`'? 整庫備份文件名.sql >> 提取出來的sql文件名.sql
還原單張表:進入mysql數據庫,執行source /home/yxx/提取出來的sql文件名.sql
將表中某一字段值中包含“XX”的部分替換成“AA”:
update proinfo set approved_param=REPLACE(approved_param,'公共事業','公共科技事業部');
將某一字段中指定部分的內容(如‘(1111)’)替換為指定內容:
update option_code set name=replace(name,substring(name,locate('(',name),(locate(')',name)-locate('(',name)+1)),'');
添加字段:
alter table table1 add transactor varchar(10) DEFAULT NULL;
新建數據庫:
create database 數據庫名 CHARACTER SET utf8 COLLATE utf8_general_ci;
修改數據庫表名稱:
alter table briefing_water_level rename tongque_briefing_water;