day41——數值類型、完整性約束

day41

數值類型

整數類型

有符號的設置
mysql> create table t1(id tinyint); # 默認有符號,即數字前有正負號
無符號的設置
mysql> create table t1(id tinyint unsigned);
zerofill用法

若是寬度小於設定的寬度(這裏寬度爲4),則自動填充0,須要注意的是,這只是最後顯示的結果,在MySQL中實際存儲的仍是1html

用zerofill測試整數類型的顯示寬度python

mysql> create table t7(x int(3) zerofill);
    mysql> insert into t7 values
        -> (1),
        -> (11),
        -> (111),
        -> (1111);
    mysql> select * from t7;
    +------+
    | x    |
    +------+
    |  001 |
    |  011 |
    |  111 |
    | 1111 | #超過寬度限制仍然能夠存
    +------+

注意:對於整型來講,數據類型後面的寬度並非存儲長度限制,而是顯示限制,假如:int(8),那麼顯示時不夠8位則用0來填充,夠8位則正常顯示,經過zerofill來測試,存儲長度仍是int的4個字節長度。默認的顯示寬度就是可以存儲的最大的數據的長度,好比:int無符號類型,那麼默認的顯示寬度就是int(10),有符號的就是int(11),由於多了一個符號,因此咱們沒有必要指定整數類型的數據,不必指定寬度,由於默認的就可以將你存的原始數據徹底顯示mysql

int的存儲寬度是4個Bytes,即32個bit,即2**32sql

無符號最大值爲:4294967296-1數據庫

有符號最大值:2147483648-1windows

​ 有符號和無符號的最大數字須要的顯示寬度均爲10,而針對有符號的最小值則須要11位才能顯示徹底,因此int類型默認的顯示寬度爲11是很是合理的服務器

  最後:整形類型,其實沒有必要指定顯示寬度,使用默認的就oksession

MySQL的mode

查sql_mode併發

select @@sql_mode
select @@global.sql_mode

sql_mode 經常使用來解決下面這幾類問題less

  • 經過設置sql mode, 能夠完成不一樣嚴格程度的數據校驗,有效地保障數據準備性。
  • 經過設置sql model 爲寬鬆模式,來保證大多數sql符合標準的sql語法,這樣應用在不一樣數據庫之間進行遷移時,則不須要對業務sql 進行較大的修改。
  • 在不一樣數據庫之間進行數據遷移以前,經過設置SQL Mode 可使MySQL 上的數據更方便地遷移到目標數據庫中。

sql_mode經常使用值以下

簡單介紹詳情:https://www.cnblogs.com/clschao/articles/9962347.html

NO_ENGINE_SUBSTITUTION
寬鬆版——若是須要的存儲引擎被禁用或未編譯,那麼拋出錯誤。不設置此值時,用默認的存儲引擎替代,並拋出一個異常

STRICT_TRANS_TABLES
嚴格版——在該模式下,若是一個值不能插入到一個事務表中,則中斷當前的操做,對非事務表不作限制
 NO_ZERO_IN_DATE:
    在嚴格模式下,不容許日期和月份爲零

注意:MySQL5.6和MySQL5.7默認的sql_mode模式參數是不同的

  • 5.6的是NO_ENGINE_SUBSTITUTION,其實表示的是一個空值,至關於沒有什麼模式設置,能夠理解爲寬鬆模式
  • 5.7的mode是STRICT_TRANS_TABLES,也就是嚴格模式。
若是設置的是寬鬆模式,那麼咱們在插入數據的時候,即使是給了一個錯誤的數據,也可能會被接受,而且不報錯,例如:我在建立一個表時,該表中有一個字段爲name,給name設置的字段類型時char(10),若是我在插入數據的時候,其中name這個字段對應的有一條數據的長度超過了10,例如'1234567890abc',超過了設定的字段長度10,那麼不會報錯,而且取前十個字符存上,也就是說你這個數據被存爲了'1234567890',而'abc'就沒有了,可是咱們知道,咱們給的這條數據是錯誤的,由於超過了字段長度,可是並無報錯,而且mysql自行處理並接受了,這就是寬鬆模式的效果,其實在開發、測試、生產等環境中,咱們應該採用的是嚴格模式,出現這種錯誤,應該報錯纔對,因此MySQL5.7版本就將sql_mode默認值改成了嚴格模式,而且咱們即使是用的MySQL5.6,也應該自行將其改成嚴格模式,而你記着,MySQL等等的這些數據庫,都是想把關於數據的全部操做都本身包攬下來,包括數據的校驗,其實好多時候,咱們應該在本身開發的項目程序級別將這些校驗給作了,雖然寫項目的時候麻煩了一些步驟,可是這樣作以後,咱們在進行數據庫遷移或者在項目的遷移時,就會方便不少,這個看大家自行來衡量。mysql除了數據校驗以外,你慢慢的學習過程當中會發現,它可以作的事情還有不少不少,將你程序中作的好多事情都包攬了。

改成嚴格模式後可能會存在的問題

若設置模式中包含了NO_ZERO_DATE,那麼MySQL數據庫不容許插入零日期,插入零日期會拋出錯誤而不是警告。例如表中含字段TIMESTAMP列(若是未聲明爲NULL或顯示DEFAULT子句)將自動分配DEFAULT '0000-00-00 00:00:00'(零時間戳),也或者是本測試的表day列默認容許插入零日期 '0000-00-00' COMMENT '日期';這些顯然是不知足sql_mode中的NO_ZERO_DATE而報錯。

模式設置和修改方法

  • 方法一

    先執行select @@sql_mode,複製查詢出來的值並將其中的NO_ZERO_IN_DATE,NO_ZERO_DATE刪除,而後執行set sql_mode = '修改後的值'或者set session sql_mode='修改後的值';,例如:set session sql_mode='STRICT_TRANS_TABLES';改成嚴格模式
    
            此方法只在當前會話中生效,關閉當前會話就不生效了。
  • 方法二

    先執行select @@global.sql_mode,複製查詢出來的值並將其中的NO_ZERO_IN_DATE,NO_ZERO_DATE刪除,而後執行set global sql_mode = '修改後的值'。
    
            此方法在當前服務中生效,從新啓動MySQL服務後失效
  • 方法三

    在mysql的安裝目錄下,或my.cnf文件(windows系統是my.ini文件),新增 sql_mode = ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,
    添加my.cnf以下:
            [mysqld] sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER
    
            而後重啓mysql。
        此方法永久生效.固然生產環境上是禁止重啓MySQL服務的,因此採用方式二加方式三來解決線上的問題,那麼即使是有一天真的重啓了MySQL服務,也會永久生效了。

浮點型

注意:float只能精準8位,從整數開始從左往右

測試
mysql> create table t3(id float(60,30));
Query OK, 0 rows affected (1.70 sec)

mysql> create table t4(id double(60,30));
Query OK, 0 rows affected (0.88 sec)

mysql> create table t5(id decimal(60,30));
Query OK, 0 rows affected (0.96 sec)

mysql> insert into t3 values(1.1111111111111111111111);
Query OK, 1 row affected (0.13 sec)

mysql> insert into t4 values(1.1111111111111111111111);
Query OK, 1 row affected (0.22 sec)

mysql> insert into t5 values(1.1111111111111111111111);
Query OK, 1 row affected (0.09 sec)

mysql> select * from t3;
mysql> select * from t4;
mysql> select * from t5;

位類型

能夠存儲二進制數或者十六進制數

詳情請看:https://www.cnblogs.com/clschao/articles/9959559.html

日期類型

  • year
YYYY(範圍:1901~2155) ——2018
  • date
YYYY-MM-DD (範圍:1000-01-01~9999-12-31) ——2018-01-01
  • time
HH:MM:SS ——12:09:32
  • datetime
YYYY-MM-DD HH:MM:SS(範圍:1000-01-01 00:00:00~9999-12-31 23:59:59  )——2018-01-01 12:09:32

測試

mysql> create table t6(d1 year ,d2 date,d3 datetime);
Query OK, 0 rows affected (1.75 sec)

mysql> insert into t6 values(now(),now(),now());
Query OK, 1 row affected, 1 warning (0.12 sec)

mysql> select * from t6;

字符串類型

詳情:https://www.cnblogs.com/clschao/articles/9959559.html

針對char類型,mysql在存儲的時候會將不足規定長度的數據使用後面(右邊補全)補充空格的形式進行補全,而後存放到硬盤中,可是在讀取或者使用的時候會自動去掉它給你補全的空格內容,由於這些空格並非咱們本身存儲的數據,因此對咱們使用者來講是無用的。

char和varchar性能對比

以char(5)和varchar(5)來比較,加入我要存三我的名:sb,ssb1,ssbb2
    char:
      優勢:簡單粗暴,無論你是多長的數據,我就按照規定的長度來存,5個5個的存,三我的名就會相似這種存儲:sb ssb1 ssbb2,中間是空格補全,取數據的時候5個5個的取,簡單粗暴速度快
      缺點:貌似浪費空間,而且咱們未來存儲的數據的長度可能會良莠不齊

    varchar:
      varchar類型不定長存儲數據,更爲精簡和節省空間
      例如存上面三我的名的時候相似因而這樣的:sbssb1ssbb2,連着的,若是這樣存,請問這三我的名你還怎麼取出來,你知道取多長能取出第一個嗎?(超哥,我能看出來啊,那我只想說:滾犢子!)
      不知道從哪開始從哪結束,遇到這樣的問題,你會想到怎麼解決呢?還記的嗎?想一想?socket?tcp?struct?把數據長度做爲消息頭。

      
      因此,varchar在存數據的時候,會在每一個數據前面加上一個頭,這個頭是1-2個bytes的數據,這個數據指的是後面跟着的這個數據的長度,1bytes能表示2**8=256,兩個bytes表示2**16=65536,能表示0-65535的數字,因此varchar在存儲的時候是這樣的:1bytes+sb+1bytes+ssb1+1bytes+ssbb2,因此存的時候會比較麻煩,致使效率比char慢,取的時候也慢,先拿長度,再取數據。

      優勢:節省了一些硬盤空間,一個acsii碼的字符用一個bytes長度就能表示,可是也並不必定比char省,看一下官網給出的一個表格對比數據,當你存的數據正好是你規定的字段長度的時候,varchar反而佔用的空間比char要多。

Value   CHAR(4) Storage Required    VARCHAR(4)  Storage Required
''  '    '  4 bytes ''  1 byte
'ab'    'ab  '  4 bytes 'ab'    3 bytes
'abcd'  'abcd'  4 bytes 'abcd'  5 bytes
'abcdefgh'  'abcd'  4 bytes 'abcd'  5 bytes
        
      缺點:存取速度都慢
  總結:
    因此須要根據業務需求來選擇用哪一種類型來存
    其實在多數的用戶量少的工做場景中char和varchar效率差異不是很大,最起碼給用戶的感知不是很大,而且其實軟件級別的慢遠比不上硬件級別的慢,因此大家公司的運維發現項目慢的時候會加內存、換nb的硬盤,項目的效率提高的會不少,可是咱們做爲專業人士,咱們應該提出來這樣的技術點來提升效率。

    可是對於InnoDB數據表,內部的行存儲格式沒有區分固定長度和可變長度列(全部數據行都使用指向數據列值的頭指針),所以在本質上,使用固定長度的CHAR列不必定比使用可變長度VARCHAR列性能要好。於是,主要的性能因素是數據行使用的存儲總量。因爲CHAR平均佔用的空間多於VARCHAR,所以使用VARCHAR來最小化須要處理的數據行的存儲總量和磁盤I/O是比較好的。

    因此啊,兩個選哪一個均可以,若是是大型併發項目,追求高性能的時候,須要結合大家服務器的硬件環境來進行測試,看一下char和varchar哪一個更好,這也能算一個優化的點吧~~~~

枚舉類型與集合類型

測試:

枚舉類型(enum)
An ENUM column can have a maximum of 65,535 distinct elements. (The practical limit is less than 3000.)
示例:
CREATE TABLE shirts (
name VARCHAR(40),
size ENUM('x-small', 'small', 'medium', 'large', 'x-large')
                );
    INSERT INTO shirts (name, size) VALUES ('dress shirt','large'), ('t-shirt','medium'),('polo shirt','small');

  
集合類型(set) 不能爲數字,能夠變爲字符串
A SET column can have a maximum of 64 distinct members.
示例:
    CREATE TABLE myset (col SET('a', 'b', 'c', 'd'));
    INSERT INTO myset (col) VALUES ('a,d'), ('d,a'), ('a,d,a'), ('a,d,d'), ('d,a,d');

完整性約束

詳情請看:https://www.cnblogs.com/clschao/articles/9968396.html

not null 不爲空
create table t1(name char(10) not null);
default 默認值
create table t1(name char(10) not null default 'xx');
unique 惟一,字段數據不能重複
create table t1(name char(10) unique);
primary key 主鍵,約束效果:不爲空且惟一
create table t1(id int primary key);
auto_increment 自增
create table t1(id int primary key auto_increment); 前面必須是個key
foreign key 外鍵,創建表關係使用的約束條件
  • 多對一(一對多)

在多的表裏面添加一個字段,並給這個字段加foreign key,好比:
出版社對於書籍是多對一的關係
一、先建立出版社表 publish表
二、建立書籍表,外鍵寫法:
create table book(
        id int primary key,
        name char(10),
        pid int,
        foreign key(pid) references publish(id)
        );
三、先給出版社插入數據
  • 一對一關係

學生表(student)和客戶表(customer)
在數據少的表添加字段,若是同樣多隨便哪一個表都行
create table student(
        id int primary key,
        name char(10),
        cid int unique,
        foreign key(cid) references customer(id)
        );

在學生表獲取到qq

  • 多對多關係

做者表和書籍表
須要藉助第三張表來完整二者的關係記錄
第三張表最後建立
create table authortobook(
            id int primary key,
            aurhor_id int,
            book_id int,
            foreign key(author_id) references author1(id),
            foreign key(book_id) references book1(id)
            )

查找代碼:

相關文章
相關標籤/搜索