union规则
- UNION必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNION分隔(因此,如果组合4条SELECT语句,将要使用3个UNION关键字)。
- UNION中的每个查询必须包含相同的列、表达式或聚集函数(不过各个列不需要以相同的次序列出)。
- 列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐含地转换的类型(例如,不同的数值类型或不同的日期类型)。
取消重复行
UNION从查询结果集中自动去除了重复的行(换句话说,它的行为与单条SELECT语句中使用多个WHERE子句条件一样)。
mysql> select vend_id,prod_id,prod_price from products where prod_price<=5; +---------+---------+------------+ | vend_id | prod_id | prod_price | +---------+---------+------------+ | 1003 | FC | 2.50 | | 1002 | FU1 | 3.42 | | 1003 | SLING | 4.49 | | 1003 | TNT1 | 2.50 | +---------+---------+------------+ 4 rows in set (0.00 sec) mysql> select vend_id,prod_id,prod_price from products where vend_id in (1001,1002); +---------+---------+------------+ | vend_id | prod_id | prod_price | +---------+---------+------------+ | 1001 | ANV01 | 5.99 | | 1001 | ANV02 | 9.99 | | 1001 | ANV03 | 14.99 | | 1002 | FU1 | 3.42 | | 1002 | OL1 | 8.99 | +---------+---------+------------+ 5 rows in set (0.00 sec) mysql>
分条执行的时候,价格小于等于5的有4条;商品号为(1001,1002)的有4条,使用union后却只有8条?
UNION从查询结果集中自动去除了重复的行(换句话说,它的行为与单条SELECT语句中使用多个WHERE子句条件一样)。因为供应商1002生产的一种物品的价格也低于5,所以两条SELECT语句都返回该行。在使用UNION时,重复的行被自动取消。
使用union all
可查看所有匹配行。
mysql> select vend_id ,prod_id,prod_price -> from products -> where prod_price <=5 -> union all -> select vend_id ,prod_id ,prod_price -> from products -> where vend_id in(1001,1002); +---------+---------+------------+ | vend_id | prod_id | prod_price | +---------+---------+------------+ | 1003 | FC | 2.50 | | 1002 | FU1 | 3.42 | | 1003 | SLING | 4.49 | | 1003 | TNT1 | 2.50 | | 1001 | ANV01 | 5.99 | | 1001 | ANV02 | 9.99 | | 1001 | ANV03 | 14.99 | | 1002 | FU1 | 3.42 | | 1002 | OL1 | 8.99 | +---------+---------+------------+ 9 rows in set (0.00 sec)
UNION ALL为UNION的一种形式,它完成WHERE子句完成不了的工作。如果确实需要每个条件的匹配行全部出现(包括重复行),则必须使用UNION ALL而不WHERE。
排序
在用UNION组合查询时,只能使用一条ORDER BY子句,它必须出现在最后一条SELECT语句之后。
mysql> select vend_id ,prod_id,prod_price -> from products -> where prod_price <=5 -> union -> select vend_id ,prod_id ,prod_price -> from products -> where vend_id in(1001,1002) -> order by vend_id,prod_price; +---------+---------+------------+ | vend_id | prod_id | prod_price | +---------+---------+------------+ | 1001 | ANV01 | 5.99 | | 1001 | ANV02 | 9.99 | | 1001 | ANV03 | 14.99 | | 1002 | FU1 | 3.42 | | 1002 | OL1 | 8.99 | | 1003 | FC | 2.50 | | 1003 | TNT1 | 2.50 | | 1003 | SLING | 4.49 | +---------+---------+------------+ 8 rows in set (0.00 sec)
全文本搜索
ps:💥这一块强烈建议看书第18章,我已经不知道该怎么写了😭
两个最常使用的引擎为MyISAM和InnoDB,前者支持全文本搜索,而后者不支持。
样例表(productnotes表)使用MyISAM。
like和正则的限制
- 性能——通配符和正则表达式匹配通常要求MySQL尝试匹配表中所有行(而且这些搜索极少使用表索引)。这些搜索可能非常耗时。
- 明确控制——使用通配符和正则表达式匹配,很难(而且并不总是能)明确地控制匹配什么和不匹配什么。
- 智能化的结果——虽然基于通配符和正则表达式的搜索提供了非常灵活的搜索,但它们都不能提供一种智能化的选择结果的方法。
启用
一般在创建表时启用全文本搜索。CREATE TABLE语句接受FULLTEXT子句,它给出被索引列的一个逗号分隔的列表。
使用
在索引之后,使用两个函数Match()和Against()执行全文本搜索,其中Match()指定被搜索的列,Against()指定要使用的搜索表达式。
mysql> select note_text from productnotes where match(note_text) against('rabbit'); +-----------------------------------------------------------------------------------------------------------------------+ | note_text | +-----------------------------------------------------------------------------------------------------------------------+ | Customer complaint: rabbit has been able to detect trap, food apparently less effective now. | | Quantity varies, sold by the sack load. All guaranteed to be bright and orange, and suitable for use as rabbit bait. | +-----------------------------------------------------------------------------------------------------------------------+ 2 rows in set (0.01 sec)
此SELECT语句检索单个列note_text。由于WHERE子句,一个全文本搜索被执行。Match(note_text)指示MySQL针对指定的列进行搜索,Against('rabbit')指定词rabbit作为搜索文本。由于有两行包含词rabbit,这两个行被返回。
与like的区别:
mysql> select note_text from productnotes where match(note_text) against('rabbit');
贴代码不美观。。。。。。。。。。。。。。贴图
这里,在SELECT而不是WHERE子句中使用Match()和Against()。这使所有行都被返回(因为没有WHERE子句)。Match()和Against()用来建立一个计算列(别名为rank),此列包含全文本搜索计算出的等级值。等级由MySQL根据行中词的数目、唯一词的数目、整个索引中词的总数以及包含该词的行的数目计算出来。正如所见,不包含词rabbit的行等级为0(因此不被前一例子中的WHERE子句选择)。确实包含词rabbit的两个行每行都有一个等级值,文本中词靠前的行的等级值比词靠后的行的等级值高。
全文本搜索提供了简单LIKE搜索不能提供的功能。而且,由于数据是索引的,全文本搜索还相当快。
查询扩展
查询扩展不仅会展示所搜索的字符,还会找出可能与搜索相关的所有其他行。利用查询扩展,能找出可能相关的结果,即使它们并不精确包含所查找的词。
- 首先,进行一个基本的全文本搜索,找出与搜索条件匹配的所有行;
- 其次,MySQL检查这些匹配行并选择所有有用的词
- 再其次,MySQL再次进行全文本搜索,这次不仅使用原来的条件,而且还使用所有有用的词。
select note_text from productnotes where match(note_text) against('anvils' with query expansion);
这次返回了7行。第一行包含词anvils,因此等级最高。第二行与anvils无关,但因为它包含第一行中的两个词(customer和recommend),所以也被检索出来。第3行也包含这两个相同的词,但它们在文本中的位置更靠后且分开得更远,因此也包含这一行,但等级为第三。第三行确实也没有涉及anvils(按它们的产品名)。
布尔文本搜索
以布尔方式,可以提供关于如下内容的细节:
- 要匹配的词;
- 要排斥的词
- 排列提示
- 表达式分组;
- 另外一些内容。
布尔方式可不加索引,但非常慢
mysql> select note_text from productnotes where match(note_text) against('heavy' in boolean mode);
为了匹配包含heavy但不包含任意以rope开始的词的行,可使用以下查询:
mysql> select note_text from productnotes where match(note_text) against('heavy -rope*' in boolean mode);
使用案例:
使用说明
- 在索引全文本数据时,短词被忽略且从索引中排除。短词定义为那些具有3个或3个以下字符的词(如果需要,这个数目可以更改)。
- MySQL带有一个内建的非用词(stopword)列表,这些词在索引全文本数据时总是被忽略。如果需要,可以覆盖这个列表(请参阅MySQL文档以了解如何完成此工作)。
- 许多词出现的频率很高,搜索它们没有用处(返回太多的结果)。因此,MySQL规定了一条50%规则,如果一个词出现在50%以上的行中,则将它作为一个非用词忽略。50%规则不用于IN BOOLEAN MODE。
- 如果表中的行数少于3行,则全文本搜索不返回结果(因为每个词或者不出现,或者至少出现在50%的行中)。
- 忽略词中的单引号。例如,don't索引为dont。
- 不具有词分隔符(包括日语和汉语)的语言不能恰当地返回全文本搜索结果。(很可惜~~)
- 如前所述,仅在MyISAM数据库引擎中支持全文本搜索。
插入数据
单行插入
insert into 表名(列名) values (对应的值);
对于完整写法来说,每一列必须一一对应每一个值。否则插入会出问题。(可根据需要选择列)
insert into 表名 values (值);
省略写法,默认对应所有的列,即value值也必须对应所有的列。
多行插入
- 多条insert语句
- 多个value项
insert into 表名(列名) values (对应的值),(对应的值),(对应的值)......;
MySQL用单条INSERT语句处理多个插入比使用多条INSERT语句快。
插入检索出的数据
假如你想从另一表中合并客户列表到你的customers表。不需要每次读取一行,然后再将它用INSERT插入,可以使用INSERT SELECT:(这道题面试我就遇上了😭)
- 准备一张和customers相同结构的表custnew
- 给custnew 填充数据,注意主键不能重复,否则会插入失败
mysql> insert into customers select * from custnew; Query OK, 2 rows affected (0.01 sec) Records: 2 Duplicates: 0 Warnings: 0
超级简写形式,因为懒😂
正常应列出所有的列
不一定要求列名匹配,它使用的是列的位置,因此SELECT中的第一列(不管其列名)将用来填充表列中指定的第一个列,第二列将用来填充表列中指定的第二个列,如此等等。
更新和删除
更新
- 更新表中特有的行
- 更新表中所有的行
两者的区别在于语句中是否有where来限制范围。
更新客户1005的电子邮箱:
mysql> update customers set cust_email = 'abc@qq.com' -> where cust_id =1005; Query OK, 0 rows affected (0.00 sec) Rows matched: 0 Changed: 0 Warnings: 0
❗️❗️where子句非常重要,没有就更新整张表了
更新多列:
mysql> update customers set cust_email = 'abc@qq.com', cust_name = 'test_update' where cust_id =1005; Query OK, 0 rows affected (0.00 sec) Rows matched: 0 Changed: 0 Warnings: 0
如果用UPDATE语句更新多行,并且在更新这些行中的一行或多行时出一个现错误,则整个UPDATE操作被取消(错误发生前更新的所有行被恢复到它们原来的值)。为即使是发生错误,也继续进行更新,可使用IGNORE关键字,如下所示:
UPDATE IGNORE customers…
删除
- 删除表中特定的行
- 删除表中所有的行
两者的区别在于语句中是否有where来限制范围。
删除某一行:
mysql> delete from customers where cust_id = 1006; Query OK, 0 rows affected (0.00 sec)
如果没有where子句,那么将删除所有行。
如果想从表中删除所有行,不要使用DELETE。可使用TRUNCATE TABLE语句,它完成相同的工作,但速度更快(TRUNCATE实际是删除原来的表并重新创建一个表,而不是逐行删除表中的数据)。
创建和操作表
创建表
CREATE TABLE `customers` ( `cust_id` int(11) NOT NULL AUTO_INCREMENT, `cust_name` char(50) NOT NULL, `cust_address` char(50) DEFAULT NULL, `cust_city` char(50) DEFAULT NULL, `cust_state` char(5) DEFAULT NULL, `cust_zip` char(10) DEFAULT NULL, `cust_country` char(50) DEFAULT NULL, `cust_contact` char(50) DEFAULT NULL, `cust_email` char(255) DEFAULT NULL, PRIMARY KEY (`cust_id`) ) ENGINE=InnoDB;
CREATE TABLE 表名( 字段值 字段类型 是否为空(NULL|NOT NULL) 默认值(default xx)AUTO_INCREMENT(int主键自动递增), .... PRIMARY KEY (`字段值`) #指定主键 )ENGINE = 选择引擎类型;
更新表
#添加一列: alter table 表名 add 列名 类型; #删除一列: alter table 表名 drop column 列名; #定义外键: alter table orderitems add constant fk_orderitems_orders foreign key (order_num) references orders(order_num);
删除表
drop table 表名;
重命名
rename table 表名 to 更新后名字;