组合查询是执行多个查询语句(SELECT语句),并将结果作为单个查询结果集返回,这些组合查询通常称为并或符合查询。
可用UNION操作来组合数条SQL查询,利用UNION,可给出多条SELECT语句,它们的结果组合成单个结果集。
使用UNION
给出每条SELECT语句,在各条语句之间放上关键字UNION。
加入需要价格小于等于5的所有物品的一个列表,而且还想包括供应商1001,和1002生产的所有物品(不考虑价格)。可以用WHERE子句来完成,也可以使用UNION。
SELECT vend_id,prod_id,prod_price FROM products prod_price<=5;
检索价格不高于5的所有物品
SELECT vend_id,prod_id,prod_price FROM products WHERE vend_id IN(1001,1002);
使用IN找出供应商1001和1002生成的所有物品。
组合上面两条语句:
SELECT vend_id,prod_id,prid_price
FROM produces
WHERE prod_price<=5
UNION
SELECT vend_id,prod_id,prod_price
FROM produces
WHERE vend_id IN(1001,1002);
语句用UNION关键字分隔,UNION指示MYSWL执行两条SELECT语句,并且把输出组成的那个查询结果集。
UNION规则
包含或取消重复的行
UNION从查询结果集中自动去除了重复的行(它的行为与单条SELECT语句中使用多个WHERE子句一样),这是UNION的默认行为,但是也可以改变:
SELECT vend_id,prod_id,prod_price
FROM produces
WHERE prod_price<=5
UNION ALL
SELECT vend_id,prod_id,prod_price
FROM products
WHERE vend_id IN (1002,1002);
这个语句不会取消重复的行。
UNION和WHERE:
UNION几乎总是完成与多个WHERE条件相同的工作,UNION ALL是UNION的一种表现形式,它完成WHERE子句完成不了的工作,如果确实需要每个条件的匹配行全部出现(包括重复行),则必须使用UNION ALL而不是WHERE。
对组合查询结果集排序
SELECT语句的出错用ORDER BY子句排序,在用UNION组合查询时,只能用一条ORDER BY子句,它必须出现在最后一条SELECT语句之后,对于结果集,不存在用一种方式排序一部分,而是用另一种方式,排序另一部分的情况,因此不允许使用多条ORDER BY子句。
使用UNION的组合查询可以应用 不同的表。
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;
这条UNION在最后一条语句后使用了ORDER BY子句,虽然ORDER BY子句似乎是最后一条SELECT语句的组成部分,但实际上MYSQL将用它来排序所有的SELECT语句返回的所有结果。
MYSQL支持几种基本的数据库引擎,并非所有的引擎都支持全文本搜索。
两个最常使用的引擎为MYISAM和InnoDB,MYISAM正常全文本搜索,InnoDB不支持。
LIKE关键字,可以利用通配符匹配文本(和部分文本)。使用LIKE关键字,可以查找包含特殊值或部分值的行(不管这些值位于列内什么位置)
使用正则表达式,可以编写操作所需行的非常复杂的匹配模式
虽然这些搜索机制非常有用,但有几个限制:
wield进行全文本搜索,必须索引被搜索的列,而且要随着数据的改变不断地重新索引。在对表列进行适当设计后,MYSQL会自动进行所有的索引和重新索引,在索引之后,SELECT可以与Match()和Against()一起使用执行搜索。
启用全文本搜索支持
一般在创建表时启用全文本搜索,CREATE TABLE语句吉首FULLTEXT子句,它给出呗索引的一个逗号分隔的列表。
CREATE TABLE productnotes
(
node_id int NOT NULL AUTO_INCREMENT,
prod_id char(10) NOT NULL,
note_date datetime NOT NULL,
note_text text NULL,
PRIMSRY KEY(note_id),
FULLTEXT(note_text)
)ENGINE=MyISAM;
CREATE TABLE语句定义表productnotes并列出它所包含的列即可,这些列中有一个名为note_text的列,为了进行全文本搜索,MYSQL根据子句FULLTEXT(note_text)的指示对他进行索引,这里的FULLTEXT索引单个列,如果需要也可以指定多个列。
在定义之后,MYSQL自动维护该索引,在增加、更新或删除行时,索引随之自动更新。
可以在创建表时指定FULLTEXT,或者在稍后指定(在这种情况下,所有的已有数据必须立即索引)。
不要在导入数据时使用FULLTEXT,更新索引要花时间,如果正在导入数据到一个新表,此时不同构启用FULLTEXT索引,应该首先导入所有数据,然后再修改表。
进行全文本搜索
在索引之后,使用两个函数Match()和Against()指定要使用的搜索表达式。
SELECT node_text FROM productnotes WHERE Match(note_text)Against('rabbit');
在SELECT语句检索单个列note_text,由于WHERE子句,一个全文本搜索被执行,Match(note_text)指示MYSQL针对指定的两行包含词rabbit,这两个行被返回。
传递给Match()的值必须与FULLTEXT()定义中的相同,如果指定多个列,则必须列出他们(而且次序正确)
搜索不区分大小写,除非使用BINARY方式。
SELECT note_text FROM productnotes WHERE note_text LIKE '%rabbit%';
这条SELECT语句同样检索出两行,但次序不同(虽然不总是出现这种情况)
SELECT note_text,Match(note_text)Against('rabbit')AS rank FROM productnotes;
在SELECT而不是WHERE子句中使用Match()和Against()。使所有行都被返回(因为没有WHERE子句)Match()和Against()用来建立一个计算列(别名为rank)
不包含次rabbit的行等级为0,确实包含次rabbit的两个行每行都有一个等级值,文本中词靠前的行的等级制比词靠后的行的等级值高。
使用查询扩展
查询扩展用来设法放宽所返回的全文本搜索结果的范围,考虑下面的情况:想找到所有提到anvils的注释包含词anvils,但你还想找出你的搜索有关的所有其他行,即使他们不包含词anvils。
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against ('anvils');
因此只返回包含词anvils的行
SELECT note_text FROM productnotes WHERE Match(note_text)Against('anvils' WITH QUERY EXPANSION);
查询扩展极大地增加了返回的行数,但这样做也增加了实际上并不想要的行的数目。
布尔文本搜索
MYSQL支持全文本搜索的另一种方式是布尔方式。
需要提供:
即使没有FULLTEXT索引也可以使用布尔文本搜索。
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('heavy' IN BOOLESN MODE);
全文本搜索检索包含词heavy的所有行(有两行),其中使用了关键字IN BOOLEAN MODE,实际上没有指定布尔操作符。
IN BOOLEAN MODE的行为差异:虽然这个例子的结果与没有IN BOOLEAN MODE的相同,但其行为有一个重要的差别。
SELECT note_text
FROM priductnotes
WHERE Match(note_text)Against('heacy -rope*' IN BOOLEAN MODE);
匹配词heavy,但-rope*明确的只是MYSQL排除包含rope*(任何以rope开始的词,包括ropes)的行
注意:
INSERT语句一般不会产生输出
INSERT INTO Cusstomers VALUES(NULL,'Pep E. LaPew','100 Main Street',Los Angeles','CA','90046','USA',NULL,NULL);
INSERT INTO customers
(cust_name,cust_address,cust_state,cust_zip,cust_country,cust_contact,cust_email) VALUES('Pep E. LaPew','100 Main Street',Los Angeles','CA','90046','USA',NULL,NULL);
可以变换顺序。
使用INSERT SELECT从custnew中将搜友数据导入customers。SELECT语句从custnew检索出要插入的值,而不是列出他们。
SELECT中列出的每个列对应与customers表名中有多少行。
如果这个表为空,则没有行被插入,也不会产生错误,如果这个表中有数据,则多有数据都会被插入到customers中。
INSERT INTO customers
(cust_id,cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country)
SELECT cust_id,cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country FROM custnew;
不要省略WHERE子句:稍不注意就会更新表中的所有行。
UPDATE customers SET cust_email='[email protected]' WHERE cust_id=10005;
要更新的表名是customwes,SET命令用来将新值赋给被更新的列
WHERE子句是告诉MYSQL更新哪一行,没有WHERE子句,酱爆包这个电子邮箱地址更新customers表中的所有行。
可以在UPDATE语句中使用子查询。
IGNORE关键字:提供UPDATE更新多行,并且在更新这些行中的一行或多行时出现一个错误,整个UPDATE操作被取消。但是使用IGNORE关键字,即使发生错误,也继续更新。
删除某个列的值:
UPDATE customers SET cust_email=NULL WHERE cust_id=10005;
不要省略WHERE子句:因为稍不注意,就会错误地删除表中所有行。
DELETE FROM customers WHERE cust_id=10006;
从customers表中删除客户10006,如果省略WHERE语句,将会删除表中每个客户。
删除的是表的内容,而不是表
更快的删除:如果从表中删除所有行,不要使用DELETE,可使用TRUNCATE TABLE语句,完成相同的工作,但是速度更快。
CREATE TABLE orders(
order_num int NOT NULL AUTO_INCREMENT,
order_date datetime NOT NULL,
cust_id int NOT NULL,
PRIMARY KEY(order_num)
)ENGINE=InnoDB;
关键字NOT NULL:如果插入没有值的列,这将会阻止插入没有值的列。如果 试图插入没有值的列,将返回错误,且插入失败。
NULL值与空串不一样。NULL值是没有值, 它不是空串。如果指定 ' '(两个单引号,其间没有字符),这 在NOT NULL列中是允许的。空串是一个有效的值,它不是无值。NULL值用关键字NULL而不是空串指定。
主键
主键值必须唯一,表中的每个行必须唯一的主键值。
也可以创建由多个列组成的主键值
CREATE TABLE orderitems(
order_num int NOT NULL,
order_item int NOT NULL,
cust_id char(10) NOT NULL,
quantity int NOT NULL,
item_price decimal(order_num,order_item)
PRIMARY KEY (order_num,order_item)
)ENGINE=InnoDB;
使用订单号(order_num列)和订单物品(order_item列)的组合作为主键。
主键为唯一标识表的每个行和列,主键只能使用不允许NULL值的列,允许NULL的值的列不能作为唯一标识。
使用AUTO_INCREMENT
列每当增加一行时自动增量。每次 执行一个INSERT操作时,MySQL自动对该列增量
每个表只允许一个AUTO_INCREMENT列,而且它必须被索引(如,通 过使它成为主键)。
cust_id int NOT NULL AUTO_INCREMENT
指定默认值
在插入时没有给出值,此时允许使用默认值
quantity int NOT NULL DEFAULT 1
指定默认值为1
指定默认值不是使用函数,只支持常量
使用的CREATE TABLE 表语句全都已ENGINE=InnoDB语句结束。
不同引擎各自有不同的功能和特性,为不同任务选择之前的引擎来获得良好的灵活性。
在ALTER TABLE更改表结构,要给出下面信息:
ALTER TABLE vendors
ADD vend_phone CHAR(20);
给表vendors增加一个名为vend_phone的列,必须明确其数据类型。
ALTER TABLE vendors
DROP COLUMN vend_phone;
删除刚刚新增的列
ALTER TABLE还有一个用途是定义外键:
ALTER TABLE orderitems
ADD CONSTRAINT fk_orderitems_orders
FOREIGN KEY(order_num) REFEITEMS orders (order_num);
DROP TABLE customers;
删除整个表,而不是其内容
RENAME TABLE customers2 TO customers;