MYSQL
and 优先级高于 or
select * from product where id='1' or id='2' and price>=10;-----------查出id为2和price大于等于10的,或者id为2的
select * from product where (id='1' or id='2') and price>=10;-----------查出id为1或2和price大于等于10的。====select * from product where id in ('1', '2') and price >=10;
like
%可以匹配0个、一个或多个字符
select * from product where name like 'jet%';-----------查出名称以jet开头的,不管jet之后有多少字符
select * from product where name like '%ack%';-----------查出包含ack的,不管ack前后有多少字符
select * from product where name like 's%e';-----------查出以s开头e结尾的,不管s和e中间有多少字符
_(下划线)可以匹配一个字符
正则表达式
REGEXP告诉mysql他后面所跟的东西是正则表达式
select * from product where name REGEXP '1000';
.可以用来匹配任意一个字符
select * from product where name REGEXP '.000';
MySQL中的正则表达式匹配(自版本 3.23.4后)不区分大小写(即,大写和小写都匹配)。为区分大 小写,可使用BINARY关键字,如WHERE prod_name REGEXP BINARY 'JetPack .000'。
使用|,为搜索两个串之一(或者为这个串,或者为另一个串)
select * from product where name REGEXP '1000|2000';
指定一组用[和]括起来的字符,想匹配特定的字符
select * from product where name REGEXP '[123] Tom';
可使用-来定义一个范围。下面的式子功能上等同于上述数字列表:[0-9] ,范围不限于完整的集合,[1-3]和[6-9]也是合法的范围。此外,范 围不一定只是数值的,[a-z]匹配任意字母字符
select * from product where name REGEXP '[1-5] Tom';
为了匹配特殊字符,必须用\(双反斜杠)为前导。\-表示查找-,\.表示查找.。
select * from product where name REGEXP '\.';
select * from product where name REGEXP '\([0-0] sticks?\)';
select * from product where name REGEXP '[[:digit:]]{4}';
定位符
select * from product where name REGEXP '^[0-9\.]';
^的双重用途 ^有两种用法。在集合中(用[和]定义),用它 来否定该集合,否则,用来指串的开始处。
创建计算字段
拼接字段(concat)
select Concat(name, '(', country, ')') from supplier;
Concat()需要一个或多个指定的串,各个串之间用逗号分隔。
通过删除数据右侧多余的空格来整理数据,这可以 使用MySQL的RTrim()函数来完成
select Concat(name, '(', RTrim(country), ')') from supplier;
Trim函数
MySQL除了支持RTrim()(正如刚才所见,它去掉 串右边的空格),还支持LTrim()(去掉串左边的空格)以及 Trim()(去掉串左右两边的空格)。
执行算术计算
select id, quality, price, quality*price as total from orders;
使用数据处理函数
函数
文本处理函数
select name, Upper(name) as nameUp from product;
SOUNDEX是一个将任何文 本串转换为描述其语音表示的字母数字模式的算法。
日期和时间处理函数
select id, num from orders where Date(order_date) = '2020-12-3';
数值处理函数
聚集函数
AVG()函数
select AVG(price) as avg_price from product;
select AVG(price) as avg_price from product where id = '1003';
COUNT()函数
COUNT()函数有两种使用方式。
使用COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值。
使用COUNT(column)对特定列中具有值的行进行计数,忽略NULL值。
MAX()函数
select MAX(price) as max_price from product;
对非数值数据使用MAX()
虽然MAX()一般用来找出最大的数值或日期值,但MySQL允许将它用来返回任意列中的最大值,包括返回文本列中的最大值。在用于文本数据时,如果数据按相应的列排序,则MAX()返回最后一行。
NULL值 MAX()函数忽略列值为NULL的行。
MIN()函数
select MIN(price) as min_price from product;
对非数值数据使用MIN()
MIN()函数与MAX()函数类似,MySQL允许将它用来返回任意列中的最小值,包括返回文本列中的最小值。在用于文本数据时,如果数据按相应的列排序,则MIN()返回最前面的行。
NULL值 MIN()函数忽略列值为NULL的行。
SUM()函数
select SUM(quality) as sum_quality from product where order_num=20005;
函数SUM(item_price*quantity)返回订单中所有物品价钱之和,WHERE子句同样保证只统计某个物品订单中的物品
select AVG( DISTINCT price) as avg_price from product;--------使用了DISTINCT参数,因此平均值只 考虑各个不同的价格
如果指定列名,则DISTINCT只能用于COUNT()。DISTINCT不能用于COUNT(*),因此不允许使用COUNT(DISTINCT),否则会产生错误。类似地,DISTINCT必须使用列名,不能用于计算或表达式。
将DISTINCT用于MIN()和MAX() 虽然DISTINCT从技术上可用于MIN()和MAX(),但这样做实际上没有价值。一个列中的最小值和最大值不管是否包含不同值都是相同的。
组合聚集函数
select COUNT(*) AS num_items, MIN(price) AS min_price, MAX(price) AS max_price, AVG(price) AS avg_price from product;
分组数据
select id, COUNT(*) AS num_product from product GROUP BY product;
在具体使用GROUP BY子句前,需要知道一些重要的规定。
GROUP BY子句可以包含任意数目的列。这使得能对分组进行嵌套,为数据分组提供更细致的控制。
如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算(所以不能从个别的列取回数据)。
GROUP BY子句中列出的每个列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式。不能使用别名。
除聚集计算语句外,SELECT语句中的每个列都必须在GROUP BY子句中给出。
如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列中有多行NULL值,它们将分为一组。
GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。
使用WITH ROLLUP关键字,可以得到每个分组以及每个分组汇总级别(针对每个分组)的值,如下所示:
select id, COUNT(*) AS num_product from product GROUP BY product WITH ROLLUP;
过滤分组
select id, COUNT(*) AS num_product from product GROUP BY product having num_product >= 2;
HAVING和WHERE的差别
这里有另一种理解方法,WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。这是一个重要的区别,WHERE排除的行不包括在分组中。这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组。
分组和排序
select order_num, SUM(quality*order_num) AS total from orders GROUP BY order_num having total >= 50 ORDER BY total;
SELECT子句顺序
使用子查询
select cust_name, cust_contact from customers where cust_id in (
select cust_id from orders where order_num in (
select order_num from orderitems where prod_id = 'TNT2'
)
);
select cust_name, cust_state, (select COUNT(*) from orders where orders.cust_id = customers.cust_id) as orders from customers order by cust_name;
联结表
select vend_name, prod_name, prod_price from vendors, products where vendors.vend_id = products.vend_id order by vend_name, prod_name;
等同于
select vend_name, prod_name, prod_price from vendors inner join products on vendors.vend_id = products.vend_id;
联结多个表
select prod_name, vend_name, prod_price, quantity from orderitems, products, vendors where products.vend_id = vendors.vend_id and orderitems.prod_id = products.prod_id and order_num = 20005;
select cust_name, cust_contact from customers where cust_id in (
select cust_id from orders where order_num in (
select order_num from orderitems where prod_id = 'TNT2'
)
);
等同于
select cust_name, cust_contact from customers, orders, orderitems where customers.cust_id = orders.cust_id and orderitems.order_num = orders.order_num and prod_id = 'TNT2';
创建高级联结
自联结
select prod_id, prod_name from products as p1, products as p2 where p1.vend_id = p2.vend_id and p2.prod_id = 'DTNTR';
自然连接
select c.*, o.order_num, o.order_date, oi.prod_id, oi.quantity, oi.item_price from customers as c, orders as o, orderitems as oi where c.cust_id = o.cust_id and oi.order_num = o.order_num and prod_id = 'FB';
外部联结
下面的SELECT语句给出一个简单的内部联结。它检索所有客户及其订单:
select customers.cust_id, orders.order_num from customers inner join orders on customers.cust_id = orders.cust_id;
外部联结语法类似。为了检索所有客户,包括那些没有订单的客户,可如下进行:
select customers.cust_id, orders.order_num from customers left outer join orders on customers.cust_id = orders.cust_id;
与内部联结关联两个表中的行不同的是,外部联结还包括没有关联行的行。
在使用OUTER JOIN语法时,必须使用RIGHT或LEFT关键字指定包括其所有行的表(RIGHT指出的是OUTER JOIN右边的表,而LEFT指出的是OUTER JOIN左边的表)。
使用带聚集函数的联结
select customers.cust_name, customers.cust_id, COUNT(orders.order_num) as num_ord from customers inner join orders on customers.cust_id = orders.cust_id group by customers.cust_id;
select customers.cust_name, customers.cust_id, COUNT(orders.order_num) as num_ord from customers left outer join orders on customers.cust_id = orders.cust_id group by customers.cust_id;
使用联结和联结条件
注意所使用的联结类型。一般我们使用内部联结,但使用外部联结也是有效的。
保证使用正确的联结条件,否则将返回不正确的数据。
应该总是提供联结条件,否则会得出笛卡儿积。
在一个联结中可以包含多个表,甚至对于每个联结可以采用不同的联结类型。虽然这样做是合法的,一般也很有用,但应该在一起测试它们前,分别测试每个联结。这将使故障排除更为简单。
组合查询
UNION
UNION必须要有两条或者两条以上select组成,中间由UNION关键字分隔,必须包含相同的列,列数据类型必须兼容
UNION自动去除了重复的行,如果要匹配所有的行,使用UNION ALL
在使用UNION组合查询时,只能使用一条ORDER BY 子句,必须出现在最后一条select子句后。
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;
全文本搜索
mysql支持几种基本的数据库引擎。并非所有的引擎都支持全文本搜索。最常使用的引擎MyISAM和InnoDB,MyISAM支持全文本搜索,InnoDB不支持。
要进行全文本搜索,必须索引被搜索的列,且要随着数据的改变不断的索引。
索引之后,select可与Match()和Against()一起使用执行搜索.
Match()指定被搜索的列,Against()指定要使用的搜索表达式。
CREATE TABLE productnotes
(
note_id int NOT NULL NULL AUTO_INCREMENT,
prod_id char(10) NOT NULL,
note_date datetime NOT NULL,
note_text text NULL,
PRIMARY KEY(note_id),
FULLTEXT(note_text)
) ENGINE=MyISAM;
不要在导入数据时使用FULLTEXT,先不启用FULLTEXT导入数据,导入完成之后启用FULLTEXT。
select note_text from productnotes where Match(note_text) Against('rabbit');
此语句还可以使用like完成,查出数据次序可能不同。
全文本搜索会对结果进行排序,具有较高等级的行先返回。
select note_text, Match(note_text) Against('rabbit') AS rank from productnotes;
上面语句会查出计算的等级。
查询扩展
找出所有提到ancils的注释,但是还想搜索有关的所有其他行,即使不含词anvils。
select note_text from productnotes where Match(note_text) Against('anvils' WITH QUERY EXPANSION);
布尔文本搜索
布尔方式不同于迄今为止使用的全文本搜索语法的地方在于,即使没有定义FULLTEXT索引,也可以使用它。
select note_text from productnotes where Match(note_text) Against('heavy' IN BOOLEAN MODE);
使用了关键字IN BOOLEAN MODE,但实际上没有指定布尔操作符,因此,其结果与没有指定布尔方式的结果相同。
为了匹配包含heavy但不包含任意以rope开始的词的行,可使用以下查询:
select note_text from productnotes where Match(note_text) Against('heavy -rope*' IN BOOLEAN MODE);
插入数据
单条
INSERT INTO customers(
cust_name,
cust_address,
cust_email
) VALUES(
'zz',
'jiangsu',
NULL
);
多条
INSERT INTO customers(
cust_name,
cust_address,
cust_email
) VALUES(
'zz',
'jiangsu',
NULL
),(
'xm',
'jiangsu',
NULL
);
插入检索出的数据
INSERT INTO customers(
cust_id,
cust_name,
cust_address,
cust_email
)
SELECT cust_id,
cust_name,
cust_address,
cust_email
FROM custnew;
更新和删除数据
UPTATE customers SET cust_name = 'zzw' WHERE cust_id = 1005;
UPTATE customers SET cust_name = 'zzw', cust_address = 'nt' WHERE cust_id = 1005;
DELETE FROM customers WHERE cust_id = 1006;
创建和操纵表
创建表
CREATE TABLE customers(
cust_id int NOT NULL AUTO_INCREMENT,
cust_name char(50) NOT NULL,
cust_address char(50) NULL,
cust_email char(255) NULL,
del_flag char(1) NOT NULL DEFAULT '0',
PRIMARY KEY (cust_id)
) ENGINE=InnoDB;
更新表
添加列ALTER TABLE vendors ADD vend_phone CHAR(20);
删除列ALTER TABLE vendors DROP vend_phone CHAR(20);
定义外键
ALTER TABLE orders ADD CONSTRAINT fk_orders_customers FOREIGN KEY (cust_id) REFERENCES customers (cust_id);
删除表
DROP TABLE customer;
重命名表
RENAME TABLE customer TO customers;
RENAME TABLE customer TO customers, order TO orders;
使用视图
CREATE VIEW productcustomers AS SELECT cust_name, cust_contact, prod_id FROM customers, orders, orderitems WHERE customers.cust_id = orders.cust_id AND orderitems.order_num = orders.order_num;
重新格式化数据
CREATE VIEW vendorlocations AS SELECT Concat(RTrim(vend_name), '(', RTrim(vend_country), ')') AS vend_title FROM vendors ORDER BY vend_name;
过滤数据
CREATE VIEW customeremail AS SELECT cust_id, cust_name, cust_email FROM customers WHERE cust_email IS NOT NULL;
计算字段
CREATE VIEW orderitemsexpanded AS SELECT order_num, prod_id, quantity, tiem_price, quantity*item_price AS total FROM orderitems;
使用存储过程
创建存储过程
CREATE PROCEDURE productpricing()
BEGIN
SELECT Avg(prod_price) AS priceaverage
FROM products;
END;
用CREATE PROCEDURE语句定义存储过程,如果存在参数,将他们在()中列举出来。
使用此存储过程,CALL productpricing();就可以得出平均价格
删除存储过程
DROP PROCEDURE productpricing;
使用此语句,存储过程不存在就会报错。使用DROP PROCEDURE IF EXISTS就可以避免。
使用参数
CREATE PROCEDURE productpricing(
OUT pl DECIMAL(8,2),
OUT ph DECIMAL(8,2),
OUT pa DECIMAL(8,2)
)
BEGIN
SELECT Min(prod_price)
INTO pl
FROM products;
SELECT Max(prod_price)
INTO ph
FROM products;
SELECT Avg(prod_price)
INTO pa
FROM products;
END;
pl存储产品最低价格,ph存储产品最高价格,pa存储产品平均价格。关键字OUT指出相应的参数用来从存储过程传出一个值(返回给调用者)。MySQL支持IN(传递给存储过程)、OUT(从存储过程传出,如这里所用)和INOUT(对存储过程传入和传出)类型的参数。
调用
CALL productpricing(
@pricelow,
@pricehigh,
@priceaverage
);
使用此语句并不显示任何数据,使用下面语句可显示
SELECT @priceaverage;
SELECT @pricehigh, @pricelow, @priceaverage;
CREATE PROCEDURE ordertotal(
IN onnumber INT,
OUT ototal DECIMAL(8,2)
)
BEGIN
SELECT Sum(item_price*quantity)
FROM orderitems
WHERE order_num = onumber
INTO ototal;
END;
onumber定义为IN,因为订单号被传入存储过程。ototal定义为OUT,因为要从存储过程返回合计。SELECT语句使用这两个参数,WHERE子句使用onumber选择正确的行,INTO使用ototal存储计算出来的合计。
调用
CALL ordertotal(20005, @total);
SELECT @total;
建立智能存储过程
CREATE PROCEDURE ordertotal(
IN onnumber INT,
IN taxable BOOLEAN,
OUT ototal DECIMAL(8,2)
) COMMENT 'Obtain order total, optionally adding tax'
BEGIN
-- Declare variable for total
DECLARE total DECIMAL(8,2);
-- Declare tax percentage
DECLARE taxrate INT DEFAULT 6;
-- Get the orde total
SELECT Sum(item_price*quantity)
FROM orderitems
WHERE order_num = onumber
INTO total;
-- Is this taxable
IF taxable THEN
-- Yes, so add taxrate to the total
SELECT total+(total/100*taxrate) INTO total;
END IF;
-- And finally, save to out variable
SELECT total INTO ototal;
END;
DECLARE语句定义了两个局部变量。DECLARE要求指定变量名和数据类型,它也支持可选的默认值。
SELECT语句已经改变,因此其结果存储到total(局部变量)而不是ototal。IF语句检查taxable是否为真,如果为真,则用另一SELECT语句增加营业税到局部变量total。最后,用另一SELECT语句将total(它增加或许不增加营业税)保存到ototal。
调用
CALL ordertotal(20005, 0, @total);
SELECT @total;
CALL ordertotal(20005, 1, @total);
SELECT @total;
BOOLEAN值指定为1表示真,指定为0表示假(实际上,非零值都考虑为真,只有0被视为假)
检查存储过程
显示创建存储过程的CREATE语句
SHOW CREATE PROCEDURE ordertotal;
获得包括何时、由谁创建等详细信息的存储过程列表,使用SHOW PROCEDURE STATUS
加限制SHOW PROCEDURE STATUS LIKE 'ordertotal';
使用游标
创建游标
CREATE PROCEDURE processorders()
BEGIN
DECLARE ordernumbers CURSOR
FOR
SELECT order_num FROM orders;
END;
DECLARE语句用来定义和命名游标,这里为ordernumbers。存储过程处理完成后,游标就消失(因为它局限于存储过程)。
打开和关闭游标
OPEN ordernumbers;
CLOSE ordernumbers;
使用游标数据
CREATE PROCEDURE processorders()
BEGIN
-- Declare local variables
DECLARE o INT;
-- Declare the cursor
DECLARE ordernumbers CURSOR
FOR
SELECT order_num FROM orders;
-- Open the cursor
OPEN ordernumbers;
-- Get order number
FETCH ordernumbers INTO o;
-- Close the cursor
CLOSE ordernumbers;
END;
其中FETCH用来检索当前行的order_num列(将自动从第一行开始)到一个名为o的局部声明的变量中。
CREATE PROCEDURE processorders()
BEGIN
-- Declare local variables
DECLARE done BOOLEAN DEFAULT 0;
DECLARE o INT;
-- Declare the cursor
DECLARE ordernumbers CURSOR
FOR
SELECT order_num FROM orders;
-- Declare continue handler
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
-- Open the cursor
OPEN ordernumbers;
-- Loop through all rows
REPEAT
-- Get order number
FETCH ordernumbers INTO o;
-- End of loop
UNTIL done END REPEAT;
-- Close the cursor
CLOSE ordernumbers;
END;
FETCH是在REPEAT内,因此它反复执行直到done为真(由UNTIL done END REPEAT;规定)。为使它起作用,用一个DEFAULT 0(假,不结束)定义变量done。
CONTINUE HANDLER,它是在条件出现时被执行的代码。这里,它指出当SQLSTATE '02000'出现时,SET done=1。SQLSTATE '02000'是一个未找到条件,当REPEAT由于没有更多的行供循环而不能继续时,出现这个条件。
CREATE PROCEDURE processorders()
BEGIN
-- Declare local variables
DECLARE done BOOLEAN DEFAULT 0;
DECLARE o INT;
DECLARE t DECIMAL(8,2);
-- Declare the cursor
DECLARE ordernumbers CURSOR
FOR
SELECT order_num FROM orders;
-- Declare continue handler
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
-- Create a table to store the results
CREATE TABLE IF NOT EXISTS ordertotals(
order_num INT,
total DECIMAL(8,2)
);
-- Open the cursor
OPEN ordernumbers;
-- Loop through all rows
REPEAT
-- Get order number
FETCH ordernumbers INTO o;
--Get the total for this order
CALL ordertotal(o, 1, t);
--Insert order and total into ordertotals
INSERT INTO ordertotals(order_num, total) VALUES(o, t);
-- End of loop
UNTIL done END REPEAT;
-- Close the cursor
CLOSE ordernumbers;
END;
使用触发器
触发器是MySQL响应以下任意语句而 自动执行的一条MySQL语句(或位于BEGIN和END语句之间的一组语句):DELETE、INSERT、UPDATE
创建触发器
CREATE TRIGGER newproduct AFTER INSERT ON products FOR EACH ROW SELECT 'Product added';
CREATE TRIGGER用来创建名为newproduct的新触发器。
AFTER INSERT,所以此触发器将在INSERT语句成功执行后执行。
FOR EACH ROW,因此代码对每个插入行执行。
这里文本Product added将对每个插入的行显示一次。
每个表最多支持6个触发器(每条INSERT、UPDATE和DELETE的之前和之后)。单一触发器不能与多个事件或多个表关联,所以,如果需要一个对INSERT和UPDATE操作执行的触发器,则应该定义两个触发器。
删除触发器
DROP TRIGGER newproduct;
使用触发器
在INSERT触发器代码内,可引用一个名为NEW的虚拟表,访问被插入的行;
在BEFORE INSERT触发器中,NEW中的值也可以被更新(允许更改被插入的值);
对于AUTO_INCREMENT列,NEW在INSERT执行之前包含0,在INSERT执行之后包含新的自动生成值。
CREATE TRIGGER neworder AFTER INSERT ON orders FOR EACH ROW SELECT NEW.order_num;
在插入一个新订单到orders表时,MySQL生成一个新订单号并保存到order_num中。触发器从NEW. order_num取得这个值并返回它。此触发器必须按照AFTER INSERT执行,因为在BEFORE INSERT语句执行之前,新order_num还没有生成。对于orders的每次插入使用这个触发器将总是返回新的订单号。
DELETE触发器
在DELETE触发器代码内,你可以引用一个名为OLD的虚拟表,访问被删除的行;
OLD中的值全都是只读的,不能更新。
CREATE TRIGGER deleteorder BEFORE DELETE ON orders FOR EACH ROW
BEGIN
INSERT INTO archive_orders(
order_num,
order_date,
cust_id
)VALUES(
OLD.order_num,
OLD.order_date,
OLD.cust_id
);
END;
在任意订单被删除之前,使用一条INSERT语句将OLD中的值保存到archive_orders的表中。
UPDATE触发器
在UPDATE触发器代码中,你可以引用一个名为OLD的虚拟表访问以前(UPDATE语句前)的值,引用一个名为NEW的虚拟表访问新更新的值;
在BEFORE UPDATE触发器中,NEW中的值可能也被更新(允许更改将要用于UPDATE语句中的值);
OLD中的值全都是只读的,不能更新。
CREATE TRIGGER updateevendor BEFORE UPDATE ON vendors FOR EACH ROW SET NEW.vend_state = Upper(NEW.vend_state);
每次更新一个行时,NEW.vend_state中的值(将用来更新表行的值)都用Upper(NEW.vend_state)替换。
管理事务处理
事务(transaction)指一组SQL语句;
回退(rollback)指撤销指定SQL语句的过程;
提交(commit)指将未存储的SQL语句结果写入数据库表;
保留点(savepoint)指事务处理中设置的临时占位符(place-holder),你可以对它发布回退(与回退整个事务处理不同)。
开始事务
START TRANSACTION;
使用ROLLBACK
SELECT * FROM ordertotals;
START TRANSACTION;
SELECT * FROM ordertotals;
ROLLBACK;
SELECT * FROM ordertotals;
使用COMMIT
START TRANSACTION;
DELETE FROM orderitems WHERE order_num = 20010;
DELETE FROM orders WHERE order_num = 20010;
COMMIT;
使用保留点
SAVEPOINT delete1;
ROLLBACK TO delete1;
更改默认的提交行为
SET autocommit=0;
autocommit标志决定是否自动提交更改,不管有没有COMMIT语句。设置autocommit为0(假)指示MySQL不自动提交更改(直到autocommit被设置为真为止)。