MySQL 大雜匯

MySQL中int(M)和tinyint(M)數值類型中M值的意義

在一開始接觸MySQL數據庫時,對於int(M)及tinyint(M)兩者數值類型後面的M值理解是最多能夠插入數據庫中的值不能大於M;

後來工作後,也是一邊學習一邊使用,之後的理解是其中的M的意思是插入數據庫中的值的字符長度不能大於M,例如,int(4),想要插入1234,1234的字符長度是4,就正好可以插入數據庫,12341就不行,因爲是5個字符長度,這也都是道聽途說,自己從來沒有驗證過;

如今,由於面試中經常會被問到有關數據庫方面的知識,今天也想着深入瞭解下這個M代表的含義(上述兩個理解都是錯誤的)。

首先,我們創建一個數據表test:

mysql> CREATE TABLE test(
    -> id1 int(1),
    -> id2 tinyint(1)
    ->);

我們給id1定義爲int,並設置字符長度爲1,id2定義爲tinyint,也設置字符長度爲1;

然後分別插入值127,127,結果發現,兩者都插入到了數據表中:

mysql> INSERT INTO test(id1,id2) values(127,127);//運行成功

結果是插入成功的,從此次測試已經可以知道,我之前的想法都是錯誤的,接下來我們再做一個實驗,插入數據128,128,即id=128,id2=128:

mysql> INSERT INTO test(id1,id2) values(128,128);//運行失敗:ERROR 1264 (22003):Out of range value for column 'id2' at row 1

出錯了,int類型的id1插入成功了,tinyint類型的id2提示超出了範圍,這是爲什麼呢?

首先,我們先要了解一個基礎知識點,就是下面這張表:(摘自W3C教程)

上述表格中的數值類型都是定長的,也就是說,無論你存的數值是多少,多大或者多小,佔用的字節大小都是固定的。例如,之前設置的int(1),雖然M值是1個字符,但是它所佔用的空間大小永遠都是4個字節的大小,換句話說就是,你可以存入有符號整型從-2 147 483 648到2 147 483 647包括這兩個數的中間任何一個數。int(1)和int(11)佔用的是4個字節,可以存入上述這些數,tinyint(1)和tinyint(4)佔用的是1個字節,可以存入從-128到127的數,這也是爲什麼之前的一次試驗,int(1)插入128成功,而tinyint(1)插入128卻提示超出長度。

那麼,這個M值到底代表什麼意思呢?

到這裏,我們已經可以發現,M值即使設置爲1,它也可以存入字符長度大於1的值,那麼,如果存入的字符長度小於1會怎麼樣?我們來試一試:

先將id1的類型更改爲int(2),然後插入數據id1=1:

mysql> ALTER TABLE test Modify id1 int(2);
mysql> INSERT INTO test(id1) values(1);//運行成功,說明值1已經插入到test表中

我們查詢一下表中的數據,看看結果具體如何:

複製代碼

mysql> SELECT * FROM test;
+------+
|  id1 |
+------+
|   1  |
+------+

複製代碼

接下來,我們再修改一下id1的填充數據類型zerofill(表示用0填充),這裏先知道如何操作即可,我們再從結果得出結論:

複製代碼

mysql> ALTER TABLE test MODIFY id1 int(2) zerofill;
mysql> SELECT * FROM test;
+------+
|  id1 |
+------+
|  01  |
+------+

複製代碼

現在是不是有些清楚了。我們設置的M值是2,沒有設置zerofill用0填充時,對於操作沒有任何影響,而設置了zerofill後,我們可以清楚地看到值1字符數不足M值,左前位置補0。我們也可以將M值設置成別的大小進行多次測試,這裏就不進行測試了。

需要強調的是,不同的數據類型中的M值意義是不一樣的,我們這裏僅討論整型中的M值。

從上面我們可以得到如下的結論:

1、整數型的數值類型已經限制了取值範圍,有符號整型和無符號整型都有,而M值並不代表可以存儲的數值字符長度,它代表的是數據在顯示時顯示的最小長度;

2、當存儲的字符長度超過M值時,沒有任何的影響,只要不超過數值類型限制的範圍;

3、當存儲的字符長度小於M值時,只有在設置了zerofill用0來填充,才能夠看到效果,換句話就是說,沒有zerofill,M值就是無用的。

 

總結:int(11),tinyint(1),bigint(20),後面的數字,不代表佔用空間容量。而代表最小顯示位數。這個東西基本沒有意義,除非你對字段指定zerofill。

所以我們在設計mysql數據庫時,建表時,mysql會自動分配長度:int(11)、tinyint(4)、smallint(6)、mediumint(9)、bigint(20)。

所以,就用這些默認的顯示長度就可以了。不用再去自己填長度,比如搞個int(10)、tinyint(1)之類的,基本沒用。而且導致表的字段類型多樣化。

參考博客:http://www.cnblogs.com/stringzero/p/5707467.html


MySQL當記錄不存在時insert,當記錄存在時更新;網上基本有三種解決方法

第一種:

示例一:insert多條記錄

假設有一個主鍵爲 client_id 的 clients 表,可以使用下面的語句:

複製代碼

INSERT INTO clients
(client_id, client_name, client_type)
SELECT supplier_id, supplier_name, 'advertising'
FROM suppliers
WHERE not exists (select * from clients
where clients.client_id = suppliers.supplier_id);

複製代碼

 

示例一:insert單條記錄

複製代碼

INSERT INTO clients
(client_id, client_name, client_type)
SELECT 10345, 'IBM', 'advertising'
FROM dual
WHERE not exists (select * from clients
where clients.client_id = 10345);

複製代碼

使用 dual 做表名可以讓你在 select 語句後面直接跟上要insert字段的值,即使這些值還不存在當前表中

 

第二種:INSERT 中 ON DUPLICATE KEY UPDATE的使用

 

如果您指定了ON DUPLICATE KEY UPDATE,並且insert行後會導致在一個UNIQUE索引或PRIMARY KEY中出現重複值,則執行舊行UPDATE。

例如,如果列a被定義爲UNIQUE,並且包含值1,則以下兩個語句具有相同的效果:

INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
UPDATE table SET c=c+1 WHERE a=1;

如果行作爲新記錄被insert,則受影響行的值爲1;如果原有的記錄被更新,則受影響行的值爲2。

註釋:如果列b也是唯一列,則INSERT與此UPDATE語句相當:

UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;

如果a=1 OR b=2與多個行向匹配,則只有一個行被更新。通常,您應該儘量避免對帶有多個唯一關鍵字的表使用ON DUPLICATE KEY子句。

您可以在UPDATE子句中使用VALUES(col_name)函數從INSERT...UPDATE語句的INSERT部分引用列值

換句話說,如果沒有發生重複關鍵字衝突,則UPDATE子句中的VALUES(col_name)可以引用被insert的col_name的值

本函數特別適用於多行insert。 VALUES()函數只在INSERT...UPDATE語句中有意義,其它時候會返回NULL

示例:

INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);

本語句與以下兩個語句作用相同:

INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=3;
INSERT INTO table (a,b,c) VALUES (4,5,6) ON DUPLICATE KEY UPDATE c=9;

當您使用ON DUPLICATE KEY UPDATE時,DELAYED選項被忽略。

第三種:REPLACE語句

我們在使用數據庫時可能會經常遇到這種情況。

如果一個表在一個字段上建立了唯一索引,當我們再向這個表中使用已經存在的鍵值insert一條記錄,那將會拋出一個主鍵衝突的錯誤。

當然,我們可能想用新記錄的值來覆蓋原來的記錄值。如果使用傳統的做法,必須先使用DELETE語句刪除原先的記錄,然後再使用

INSERTinsert新的記錄。而在MySQL中爲我們提供了一種新的解決方案,這就是REPLACE語句。使用REPLACEinsert一條記錄時,

如果不重複,REPLACE就和INSERT的功能一樣,如果有重複記錄,REPLACE就使用新記錄的值來替換原來的記錄值。

 

使用REPLACE的最大好處就是可以將DELETE和INSERT合二爲一,形成一個原子操作。這樣就可以不必考慮在同時使用DELETE和INSERT時添加事務等複雜操作了。

在使用REPLACE時,表中必須有唯一索引,而且這個索引所在的字段不能允許空值,否則REPLACE就和INSERT完全一樣的。

在執行REPLACE後,系統返回了所影響的行數,如果返回1,說明在表中並沒有重複的記錄,如果返回2,說明有一條重複記錄,系統自動先調用了 DELETE刪除這條記錄,

然後再記錄用INSERT來insert這條記錄。如果返回的值大於2,那說明有多個唯一索引,有多條記錄被刪除和insert

 

REPLACE的語法和INSERT非常的相似,如下面的REPLACE語句是insert或更新一條記錄

REPLACE INTO users (id,name,age) VALUES(123, '趙本山', 50);

insert多條記錄:

REPLACE INTO users(id, name, age) VALUES(123, '趙本山', 50), (134,'Mary',15);

REPLACE也可以使用SET語句

REPLACE INTO users SET id = 123, name = '趙本山', age = 50;

上面曾提到REPLACE可能影響3條以上的記錄,這是因爲在表中有超過一個的唯一索引。

在這種情況下,REPLACE將考慮每一個唯一索引,並對每一個索引對應的重複記錄都刪除,然後insert這條新記錄。

假設有一個table1表,有3個字段a, b, c。它們都有一個唯一索引。

CREATE TABLE table1
(a INT NOT NULL UNIQUE,
b INT NOT NULL UNIQUE,
c INT NOT NULL UNIQUE);

假設table1中已經有了3條記錄

複製代碼

a b c

1 1 1

2 2 2

3 3 3

複製代碼

下面我們使用REPLACE語句向table1中insert一條記錄。

REPLACE INTO table1(a, b, c) VALUES(1,2,3);

返回的結果如下

Query OK, 4 rows affected (0.00 sec)

在table1中的記錄如下

a b c

1 2 3

我們可以看到,REPLACE將原先的3條記錄都刪除了,然後將(1, 2, 3)insert

 

總結:雖然沒有具體測試,

感覺第一種最費資源了(只是感覺),不過你要是沒有主鍵的話也只能用他了

第二種和第三種的區別是:

  1)insert是先嚐試insert,若主鍵存在則更新。REPLACE是先嚐試insert,若主鍵存在則刪除原紀錄再insert。

  2)如果有多個唯一關鍵字發生衝突(不同關鍵字的衝突發生在不同記錄),比如現在有2個字段2條記錄衝突了(沒條記錄衝突一個字段),則insert是選擇排序後在前面的一條進行更新,REPLACE是刪除那兩條記錄,

然後insert新記錄


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章