深入浅出SQL(7)-ALTER

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baby_hua/article/details/82189153

该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动!

ALTER:改写历史

使用ALTER命令:

    可以修改表,对其套用新的设计方法,且不会影响现有数据;

    本章还会学到规范化的意义,我们要规范化我们的表;

由于重新建了本地数据库,相应的练习数据表需要重新建;

    新建数据库:hq_drinks;

    新建表:summer_drinks;

建表SQL:

mysql> CREATE TABLE summer_drinks

    -> (

    -> drink_name VARCHAR(30),

    -> cost DEC(4,2),

    -> burdening VARCHAR(50)

    -> );

Query OK, 0 rows affected (0.02 sec)

新建的summer_drinks表:

    包含了三个字段:饮品名称-drink_name、价格-cost、配料-burdening;

mysql> desc summer_drinks;

+------------+--------------+------+-----+---------+-------+

| Field      | Type         | Null | Key | Default | Extra |

+------------+--------------+------+-----+---------+-------+

| drink_name | varchar(30)  | YES  |     | NULL    |       |

| cost       | decimal(4,2) | YES  |     | NULL    |       |

| burdening  | varchar(50)  | YES  |     | NULL    |       |

+------------+--------------+------+-----+---------+-------+

我们需要一些改变:

    我们对该表新插入若干条数据;

    我们现在想对这张表做一些改变,但又不想丢失数据;

当前的表内容:

mysql> SELECT * FROM summer_drinks;

+------------------+-------+------------------+

| drink_name       | cost  | burdening        |

+------------------+-------+------------------+

| Apple Juice      | 15.50 | Apple,Water      |

| Orange Juice     | 15.50 | Orange,Water     |

| Banana Juice     | 15.50 | Banana,Water     |

| Strawberry Juice | 15.50 | Strawberry,Water |

+------------------+-------+------------------+

比如,我们想新添加一列表示饮品的量,单位是ml:

    我们可以使用ALTER轻松添加它;

添加新列:

mysql> ALTER TABLE summer_drinks

    -> ADD COLUMN milliliter INT;

指定新列的安放位置:

    删除刚刚添加的列,重新添加,我们来看看如何指定该列的安放位置;

删除指定列:

mysql> ALTER TABLE summer_drinks

    -> DROP COLUMN milliliter;

也可以删除多列:

mysql> ALTER TABLE drinks_sum

    -> DROP COLUMN burdening_main,

    -> DROP COLUMN burdening_sub;

使用关键字AFTER:

    和之前我们接触的FIRST类似;

mysql> ALTER TABLE summer_drinks

    -> ADD COLUMN milliliter INT AFTER cost;

现在我们再来看下表:

mysql> SELECT * FROM summer_drinks;

+------------------+-------+------------+------------------+

| drink_name       | cost  | milliliter | burdening        |

+------------------+-------+------------+------------------+

| Apple Juice      | 15.50 |       NULL | Apple,Water      |

| Orange Juice     | 15.50 |       NULL | Orange,Water     |

| Banana Juice     | 15.50 |       NULL | Banana,Water     |

| Strawberry Juice | 15.50 |       NULL | Strawberry,Water |

+------------------+-------+------------+------------------+

关键字AFTER:

    紧跟在新添加的列的名称后面;

    AFTER是可选关键字;如果不使用它,新列则会添加到表的最后;

类似的我们还有:

    FIRST、AFTER column、BEFORE column、LAST;

    另外还有SECOND、THIRD可供使用;

修改表:

    根据前一章关于ALTER的介绍,我么实践了添加新列;现在我们来看看如何修改表;

    对于上边我们新建的summer_drinks表,之所以要修改它,是因为它并不符合我们规范化的要求;

        burdening不满足原子性数据的要求,表没有主键;

        其他名称我们也想统一下;

   

ALTER命令:

    几乎能让你改变表里的一切,而且不需重新插入数据;

    但要小心,如果改变的是列的类型,可能会有遗失数据的风险;

承担具体修改的关键字:

1.CHANGE:

    可同时改变现有列的名称和数据类型;(修改数据类型可能会遗失数据)

2.MODIFY:

    修改现有列的数据类型或位置;(修改数据类型可能会遗失数据)

3.ADD:

    在当前表中添加一列——可自选类型;ADD新列的时候,可以指定新列的位置;

4.DROP:

    从表中删除某列;(对应的也会删除数据)    

5.其他关键字,比如RENAME等,实践时会介绍;

修改表名:

我们尝试为summer_drinks表起一个更加简洁的名字:

mysql> ALTER TABLE summer_drinks

    -> RENAME TO drinks_sum;

修改列名:

我们尝试修改milliliter列名为meter:

mysql> ALTER TABLE drinks_sum

    -> CHANGE COLUMN milliliter meter INT;

现在,我们为表添加两列:drink_id,drink_des,分别表示饮品的编号和描述;

mysql> ALTER TABLE drinks_sum

    -> ADD COLUMN drink_id CHAR(2) FIRST,

    -> ADD COLUMN drink_des VARCHAR(100);

现在我们的表是这样的:

mysql> SELECT * FROM drinks_sum;

+----------+------------------+-------+-------+------------------+-----------+

| drink_id | drink_name       | cost  | meter | burdening        | drink_des |

+----------+------------------+-------+-------+------------------+-----------+

|     NULL | Apple Juice      | 15.50 |  NULL | Apple,Water      | NULL      |

|     NULL | Orange Juice     | 15.50 |  NULL | Orange,Water     | NULL      |

|     NULL | Banana Juice     | 15.50 |  NULL | Banana,Water     | NULL      |

|     NULL | Strawberry Juice | 15.50 |  NULL | Strawberry,Water | NULL      |

+----------+------------------+-------+-------+------------------+-----------+

重新装备列:

    我们已经掌握了修改表名、修改列名,很好,但还不够,对于我们当前的表结构我们还需要:

    1)添加主键:将drink_id列作为主键,名字替换为更简洁的id,同时列的类型也需要替换为关键字AUTO_INCREMENT需要的整数类型;

    2)数据原子性支持:burdening列,拆分成burdening_main、burdening_sub;

ALTER和CHANGE:

    我们来看看如何使用这两个关键字实现主键的需求:

        把drink_id列名修改为id;

        修改id的数据类型为INT;

        添加AUTO_INCREMENT,将其标注为主键;

    同时修改数据类型和名称,使用关键字CHANGE最为合适;

mysql> ALTER TABLE drinks_sum

    -> CHANGE COLUMN drink_id id INT NOT NULL AUTO_INCREMENT,

    -> ADD PRIMARY KEY(id);

Query OK, 4 rows affected (0.06 sec)

CHANGE COLUMN之后是旧列名 之后 紧跟 新列名及其数据类型、限制条件等;在上述命令中我们指定了主键;

现在的表是这样的:

mysql> SELECT * FROM drinks_sum;

+----+------------------+-------+-------+------------------+-----------+

| id | drink_name       | cost  | meter | burdening        | drink_des |

+----+------------------+-------+-------+------------------+-----------+

|  1 | Apple Juice      | 15.50 |  NULL | Apple,Water      | NULL      |

|  2 | Orange Juice     | 15.50 |  NULL | Orange,Water     | NULL      |

|  3 | Banana Juice     | 15.50 |  NULL | Banana,Water     | NULL      |

|  4 | Strawberry Juice | 15.50 |  NULL | Strawberry,Water | NULL      |

+----+------------------+-------+-------+------------------+-----------+

如果需要改变两个列,我们可以以一条SQL语句来实现:只需要在ALTER TABLE后放两个CHANGE COLUMN,中间以逗号隔开;

注意数据类型也修改了:

    如果把数据改成另一种类型,你可能会丢失数据;

    如果你想改变的数据类型和原始数据类型不兼容,命令则不会执行;但真正的惨剧可能发生在类型兼容的情况下,你的数据可能被截断;

    例如:从varchar(10)改为char(1),数据’Bonzo’将被砍成’B’;

    相同的问题也会出在数字类型上,如精度问题引起的数据丢失;

只改变数据类型:

    可以CHANGE COLUMN column column NEWTYPE;但我们有更简单的方式;

    我们可以使用关键字MODIFY,他只会修改列的类型而不会干涉他的名称;

mysql> ALTER TABLE drinks_sum

    -> MODIFY COLUMN drink_des VARCHAR(50);

这里注意:我们指定的新数据类型长度是50,原来是100,我们需要确定新类型不会造成旧数据被截断;

改变列的顺序:

    创建表后就无法真正地改变列的顺序了;最多只能在指定位置添加新列,然后删除旧列并指定位置,但这样会丢失数据;

    实际上列的顺序并不会造成问题,因为在SELECT查询中可以指定查询结果的列顺序;硬盘里存储数据的顺序并不重要;

    SELECT column3,column2,column1 FROM table;

重新认识DROP:

    更准确的来说,应该叫“卸除”;对于用不到的列,可以把它卸除DROP;

    你的列越多,RDBMS的工作就越累,所占空间也越大;查询变慢、计算机的处理器也会运行得很辛苦;

一旦你卸除列,原本存储在该列中的一切内容都会跟着被卸除;因此使用DROP COLUMN时需要务必小心;或许应该先以SELECT选取出列,确定是我们要删除的列;

我们可以用一个ALTER TABLE,配合之前我们接触到的RENAME TO、ADD COLUMN、CHANGE COLUMN等子句进行搭配使用,多个子句中间以逗号分割;

没有蠢问题:

1.之前说过,MODIFY无法重新排列列的顺序,但是我们的SQL软件工具让我们重新排列他们,有是怎样做到的:

    其实软件在背后做了好多,他会把列的内容复制到临时表中,然后卸除该列,再用ALTER创建同名列名,放到指定位置,而后把临时表的内容复制到新列中,最后再删除临时表;

    一般而言,如果列中已经有内容,而且你使用的软件无法完成上述操作的话,最好不要对列的位置动手动脚,而是使用SELECT时指定顺序;

2.如果已经创建了主键,然后又意外想改成另一列,该怎样做:

    只移除主键;

ALTER TABLE table DROP PRIMARY KEY;

    对于AUTO_INCREMENT的处理可以这样:

ALTER TABLE table 

CHANGE your_id your_id INT NOT NULL AUTO_INCREMENT;

——>

ALTER TABLE table 

CHANGE your_id your_id INT NOT NULL;

    然后重新添加即可;

之所以这样做是因为:每个表中只有一列可以加上AUTO_INCREMENT,该列必须为整数类型而且不能包含NULL;

小结:

1.想要同时改变列的名称和类型时请用CHANGE;

2.只想改变数据类型时请用MODIFY;

3.DROP COLUMN的功能是从表中卸除指名的列;

4.使用RENAME改变表的名称;

5.使用FIRST、LAST、BEFORE column、AFTER column、THIRD、FOUTH等关键字,可以调整列的顺序;

6.有些RDBMS只有在添加新列的时才允许改变列的顺序;

数据原子性支持:

    burdening列,拆分成burdening_main、burdening_sub;

    使用SELECT、UPDATE时搭配ALTER TABLE。可以把使用不便,没有原子性的列调整为具有精确原子性的列;

具体的做法:

1.寻找模式:

    我们看到 饮料配料 列的文本都是以逗号隔开的主副料,所以burdening列存储的数据都具有相同的模式;

    这一模式有助于我们将其分割为更具原子性的数据;

        把逗号前的数据放在新列burdening_main;逗号后的数据放在burdening_sub;

2.抓取逗号左右部分的函数;

一些字符串函数:

1)SELECT最后/前的若干个字符:

RIGHT()和LEFT():

    可以从一个方向选出指定数量的字符;

mysql> SELECT RIGHT(burdening,5) FROM drinks_sum;

+--------------------+

| RIGHT(burdening,5) |

+--------------------+

| Water              |

| Water              |

| Water              |

| Water              |

+--------------------+

4 rows in set (0.00 sec)

2)SELECT逗号前的所有内容:

SUBSTRING_INDEX()可以撷取列值的部分,也称为子字符串(Substring);

    这个函数会找到指定字符或指定字符串前的所有内容;逗号需要用引号括起来;

mysql> SELECT SUBSTRING_INDEX(burdening,',',1) FROM drinks_sum;

+----------------------------------+

| SUBSTRING_INDEX(burdening,',',1) |

+----------------------------------+

| Apple                            |

| Orange                           |

| Banana                           |

| Strawberry                       |

+----------------------------------+

4 rows in set (0.00 sec)

SUBSTRING_INDEX()函数会寻找引号中的参数字符或字符串,取出其前边的所有内容;

最后的参数1,表示的是寻找第几个逗号,如果是2,那取出的将是第二个都好前的所有内容;

3)SELECT指定位置后的所有内容:

SUBSTRING:截取子串;

mysql> help SUBSTRING;

Name: 'SUBSTRING'

Description:

Syntax:

SUBSTRING(str,pos), SUBSTRING(str FROM pos), SUBSTRING(str,pos,len),

SUBSTRING(str FROM pos FOR len)

Examples:

mysql> SELECT SUBSTRING('Quadratically',5);

        -> 'ratically'

mysql> SELECT SUBSTRING('foobarbar' FROM 4);

        -> 'barbar'

mysql> SELECT SUBSTRING('Quadratically',5,6);

        -> 'ratica'

mysql> SELECT SUBSTRING('Sakila', -3);

        -> 'ila'

mysql> SELECT SUBSTRING('Sakila', -5, 3);

        -> 'aki'

mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);

        -> 'ki'

4)其他字符串辅助函数:

UPPER()、LOWER()、REVERSE():反转字符串里的字符排序、LTRIM()/RTRIM():清除左/右的多余空格;

LENGTH():返回字符串中的字符数量;

LOCATE(search, string):获取search在string中的位置;

mysql> SELECT SUBSTRING(burdening,1,LENGTH(burdening)) FROM drinks_sum;

+------------------------------------------+

| SUBSTRING(burdening,1,LENGTH(burdening)) |

+------------------------------------------+

| Apple,Water                              |

| Orange,Water                             |

| Banana,Water                             |

| Strawberry,Water                         |

+------------------------------------------+

4 rows in set (0.00 sec)
mysql> SELECT SUBSTRING(burdening,1, locate(',',burdening) - 1) FROM drinks_sum;

+---------------------------------------------------+

| SUBSTRING(burdening,1, locate(',',burdening) - 1) |

+---------------------------------------------------+

| Apple                                             |

| Orange                                            |

| Banana                                            |

| Strawberry                                        |

+---------------------------------------------------+

4 rows in set (0.01 sec)

值得注意的是:

    字符串的起始字符下标是1;

    字符串函数也不会改变存储在表中的内容,只是把字符串修改后的模样作为查询结果返回;

3.以现有列的内容填入新列:

1)我们新加两个列:burdening_main、burdening_sub;

mysql> ALTER TABLE drinks_sum

    -> ADD COLUMN burdening_main VARCHAR(20) AFTER burdening,

    -> ADD COLUMN burdening_sub VARCHAR(20) AFTER burdening_main;

2)使用UPDATE SET新列的值:

mysql> UPDATE drinks_sum

    -> SET burdening_main = SUBSTRING(burdening,1, LOCATE(',',burdening) - 1),burdening_sub = SUBSTRING(burdening,LOCATE(',',burdening) + 1, LENGTH(burdening) - LOCATE(',',burdening));

分析:

    我们使用UPDATE一次SET了两个列的值,由于没有WHERE子句,表中的每一行都会被设定为新值;

    当第一次遍历完成表时,这条语句抓出第一条记录的burdening列并套用函数;

    然后这条语句再运行一次,这次抓到第二行的burdening列,继续套用函数,依次类推直到结束没有任何记录符合条件为止;

为了确定我们插入的值,我们可以先用SELECT查询:

SELECT SUBSTRING(burdening,1, LOCATE(',',burdening) - 1) FROM drinks_sum;

SELECT SUBSTRING(burdening,LOCATE(',',burdening) + 1, LENGTH(burdening) - LOCATE(',',burdening)) FROM drinks_sum;

总结:

ALTER TABLE:以保留表中现有数据为前提,修改表的名称及整体结构;

ALTER搭配ADD:以你指定的顺序把列添加到表中;

ALTER搭配DROP:从表中卸除列;

ALTER搭配CHANGE:同时修改现有列的名称和类型;

ALTER搭配MODIFY:只修改现有列的类型;

String Functions:这些函数可修改字符串列的内容副本并以查询结果的形式返回,原始数据不会改变;

猜你喜欢

转载自blog.csdn.net/baby_hua/article/details/82189153
今日推荐