SELECT
作用:从一个或多个表(试图)中检索数据
注意:查询的结果列中不能部分使用distinct。distinct 关键字作用于所有的列,不仅仅是跟在其后的那一列。
示例:
数据表:
select distinct vend_id,prod_price from products;
返回:
返回前5行数据
(SQL SERVER)select TOP 5 ... from ...
(DB2) select ... from ... FETCH FRIST 5 ROWS ONLY;
(Oracle)select ... from ... where ROWNUM <=5;
(MYSQL等)select ... from ... LIMIT 5;
返回后5行数据
-- 从第5行起的5行数据
select ... from ... limit 5 offset 5;
+, ||, concat。不同数据库不一样
(SQL SERVER)select vend_name + '(' + vend_country + ')';
(DB2、pg、oracle) select vend_name || '(' || vend_country || ')';
(MYSQL)select concat(vend_name , '(' , vend_country , ')');
Rtrim(), Ltrim(),trim()
--去掉右边空格
select Rtrim(vend_name)
--去掉左边空客
select Ltrim(vend_name)
-- 去掉两边的空格
select trim(vend_name)
注意:别名的名字即可以是一个单词,也可以是一个字符串。如果是后者,字符串需要括在引号中。一般不建议使用字符串作为别名,会给客户端应用带来各种问题。因此,别名最常见的使用是将多个单词的列名重命名为一个单词的名字。
select order_num,
sum( item_price * quantity ) as order_amount
from order_items
如果省略了from子句,select就是简单的访问和处理表达式,比如’select 3*2’会返回6
函数 | 含义 | 备注 |
---|---|---|
AVG() | 平均值 | 忽略NULL值 |
MAX() MIN() | 最大值/最小值 | 忽略NULL值 |
COUNT | 特定列中具有值的行进行计数 | Count(column)忽略NULL值,Count(*)包含NULL值 |
SUM | 求和 | 忽略NULL值 |
注意:
所有聚集函数都可以使用[distinct],如COUNT(distinct product_name)
利用标准的算数操作符,所有聚集函数都可用来执行多个列上的计算,如avg(item_pricequantity)
所有聚集函数指定列名时都会忽略NULL值的行,count()则不会忽略
使用分组可以将数据分为多个逻辑组,对每个组进行聚集计算。
select vend_id ,count(*) as num_prods from products
GROUP BY vend_id
/** 执行说明
group by 子句指示DBMS按vend_id排序并分组数据,对每个vend_id而不是整个表计算num_prods一次
**/
group by 子句可以包含任意数据的列,对分组的内部再进行分组;
如果使用了嵌套分组,数据将在最后指定的分组上进行汇总;
group by 子句中列出的每一列都必须是检索列或有效的表达式(但不能是聚集函数)。如果select中使用表达式,则必须在group by子句中指定相同的表达式,不能使用别名。
大多数sql实现不允许group by 列带有长度可变的数据类型。
除聚集计算语句外,select语句中的每一列都必须在group by 子句中给出。
如果分组列中包含具有null值的行,则null将作为一个分组返回。
语句:HAVING
having是基于完整的分组而不是个别的行进行过滤的。是对select语句中的聚集函数进行过滤。
因为被分到一个组的数据的其他列的值不一定都相等,数据库不知道该返回什么。除非返回的列的值也是每个分组中的值都一样。
比如products表中的数据如下:
此时查询每个供应商提供的产品个数,3个供应商分为3组,应该为:
select vend_id ,count(*) as num_prods from products GROUP BY vend_id
如果返回的列增加一个:prod_price
select vend_id ,prod_pric,count(*) as num_prods from products GROUP BY vend_id
此时在每个分组里,prod_price的值是不一样的,数据库不知道该返回什么,就会报错。如果额外的列在同一个分组里值都一样,就不会报错。
mysql的ONLY_FULL_GROUP_BY错误
注意:如果select中返回的列不在group by中mysql会报ONLY_FULL_GROUP_BY错误,可以在列上使用any_value(),数据库会选择被分到同一组的数据里第一条数据的指定列值作为返回数据。
ONLY_FULL_GROUP_BY的语义就是确定select target list中的所有列的值都是明确语义。在此模式下,target list中的值要么是来自于聚合函数(sum、avg、max等)的结果,要么是来自于group by list中的表达式的值
MySQL提供了any_value()函数来抑制ONLY_FULL_GROUP_BY值被拒绝
any_value()会选择被分到同一组的数据里第一条数据的指定列值作为返回数据
-- 查询购买过单价>10的产品的顾客信息
select cust_id,customers.cust_name,cust_contact
from customers
where cust_id in
(select DISTINCT cust_id from orders where order_num in
(SELECT order_num from order_items WHERE quantity >10)
);
注意:
由于性能限制,不能嵌套太多的子查询
子查询的select语句只能查询单个列
/** 示例:查询每个顾客的订单总数
1.从customers表中检索顾客列表
2.对于检索出的每个顾客,统计其在orders表中的订单数目
**/
select cust_name,cust_state,
(select count(*)
from orders
where orders.cust_id = customers.cust_id) as Orders
from customers
联结符 | 含义 |
---|---|
left join /left outer join | 左外联结:包含左表的所有行,对应的右表行可能为空。 |
right join/left outer join | 右外联结:包含右表的所有行,对应的左表行可能为空。 |
join/inner join | 内联结:只包含左右表都匹配并且不为空的行 (与join相同)。建立的每个内联结都是自然联结。 |
-- 联结多个表
-- 方式一
select cust_name,
orders.order_num,
sum(item_price * quantity) as orderTotal
from customers
join orders on orders.cust_id = customers.cust_id
join order_items on orders.order_num = order_items.order_num
group by cust_name, orders.order_num
order by customers.cust_id,orders.order_num
-- 方式二
select cust_name,
orders.order_num,
sum(item_price * quantity) as orderTotal
from customers ,orders,order_items
where orders.cust_id = customers.cust_id
and orders.order_num = order_items.order_num
group by cust_name, orders.order_num
order by customers.cust_id,orders.order_num
在一个查询中从不同的表返回结构数据
对一个表执行多个查询,按一个查询返回数据
组合查询和where
任何具有多个where子句的select语句都可以作为一个组合查询
创建组合查询
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state = 'MI'
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state = 'IL'
ORDER BY cust_name;
EXCEPT(MINUS): 可用来检索只在第一个表中存在而在第二个表中不存在的行.
INTERSECT: 可用来检索两个表中都存在的行
数据crud
UPDATE
作用:更新表中的一行或多行数据
update tablename
set columname = value, …
[where …]
INSERT
作用:添加一行数据
insert into tablename [(column1,…)]
values(value1,…)
DELETE
作用:删除一行或多行数据
delete from tablename
[where …];
INSERT SELECT
作用:将select的结果插入到一个表
insert into tablename [(column1,…)]
select columns, … from tablename, …
[where …];
数据库操作
CREATE TABLE
作用:创建表
DROP TABLE IF EXISTS order_items
;
CREATE TABLE order_items
(
order_num
varchar(255) NOT NULL,
order_item
varchar(255) NOT NULL,
prod_id
varchar(255) NOT NULL,
quantity
varchar(255) NOT NULL,
item_price
varchar(255) DEFAULT NULL,
PRIMARY KEY (order_num
,order_item
),
foreign key(order_num) references orders(order_num),
foreign key(prod_id) references products(prod_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
SET FOREIGN_KEY_CHECKS = 1;
ALTER TABLE
作用:更新已存在表的结构
alter table tablename
(
add|drop column datatype [null|not null] [constraints],
add|drop column datatype [null|not null] [constraints],
...
);
COMMIT
作用:用来将事物写入数据库
commit [transaction]
CREATE INDEX
作用:用于在一个或多个列上创建索引
create index indexname
on tablename (column, ...)
CREATE PROCEDURE
作用:用于创建存储过程
commit [transaction]
CREATE VIEW
作用:用于创建一个或多个表上的新试图
create view viewnamne as
select columns, ...
from tables, ...
[where ...]
[group by ...]
[having ...];
DROP
作用:永久的删除数据库对象(表、试图、索引等)
drop index|tablename|viwe indexname|table|view name|...
ROLLBACK
作用:用于撤销一个事物块
rollback [TO savepointname]
练习题
/练习题10-1:查询每个订单号各有多少行/
select order_num ,count(*) as order_lines
from order_items
GROUP BY order_num
ORDER BY order_lines;
/练习题10-2:查询每个供应商成本最低的商品,并按成本价排序/
select vend_id,min(prod_price) as cheapest_item
from products
group by vend_id
order by cheapest_item desc;
/练习题10-3:查询最佳顾客:至少含有100个item的所有订单/
select order_num, count(*) as order_lines
from order_items
GROUP BY order_num
HAVING order_lines>3;
/练习题10-4:查询最佳顾客,订单总价值>1000的订单/
select order_num,sum(item_price*quantity) as order_amount
from order_items
GROUP BY order_num
HAVING order_amount>1000;
/**解决sql_mode=only_full_group_by
set session sql_mode=‘STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION’;
select version(), @@sql_mode;
**/
/练习题11-1:查询购买过单价>10的产品的顾客信息/
select cust_id,customers.cust_name,cust_contact
from customers
where cust_id in
(select DISTINCT cust_id from orders where order_num in
(SELECT order_num from order_items WHERE quantity >10)
);
/练习题11-2: 查询购买了prod_id为BR01的产品的顾客ID和订单日期/
select cust_id
from orders
where order_num in
(select DISTINCT order_num from order_items where prod_id = 'BR01');
select cust_id,order_date
from orders join order_items on orders.order_num = order_items.order_num
where order_items.prod_id ='BR01';
/练习题11-3: 查询购买了prod_id为BR01的产品的顾客邮件/
select cust_id,customers.cust_name,cust_email
from customers
where cust_id in
(select DISTINCT cust_id from orders where order_num in
(select DISTINCT order_num from order_items where prod_id = 'BR01'));
select customers.cust_id,customers.cust_name,cust_email
from customers
join orders on customers.cust_id = orders.cust_id
join order_items on orders.order_num = order_items.order_num
where order_items.prod_id ='BR01';
/*练习题11-4: 查询顾客的已订购金额
1.总额的查询:查询每个订单的总额,然后根据顾客ID对订单分组再计算总额
*/
select orders.cust_id,
sum(
(select sum(quantity*item_price)
from order_items
where orders.order_num = order_items.order_num
group by order_num)
)as order_amount
from orders
group by orders.cust_id
order by order_amount desc
/练习题11-5: 从products表中检索所有的产品名称,以及其已经销售的总数quant_sold/
select products.prod_name,
(select sum(quantity)
from order_items
where products.prod_id= order_items.prod_id
group by prod_id
) as quant_sold
from products
/练习题12-2查询顾客名称和订单号,以及订单总价,按顾客名称和订单号排序/
-- 个人解答:包含未下单的顾客
-- 方法一:比较笨的方法
select customers.cust_id,customers.cust_name ,ot.order_num,ot.orderTotal
from customers
left join
(select orders.order_num,cust_id,orderTotal
from orders
inner join
(select order_num,sum(item_price * quantity) as orderTotal
from order_items
group by order_num) as order_total
on orders.order_num = order_total.order_num) as ot
on customers.cust_id = ot.cust_id
order by customers.cust_id,ot.order_num;
-- 查看答案后改的方法,重点:子查询用于计算公式中
select customers.cust_id,customers.cust_name ,ot.order_num,ot.orderTotal
from customers
left join
(select order_num,
cust_id,
(select sum(item_price * quantity) from order_items where order_items.order_num = orders.order_num) as orderTotal
from orders) as ot
on customers.cust_id = ot.cust_id
order by customers.cust_id,ot.order_num
-- 查看答案后改的方法,重点:group by 可以使用多个列,多个表左关联
select cust_name,
orders.order_num,
sum(item_price * quantity) as orderTotal
from customers
left join orders on orders.cust_id = customers.cust_id
left join order_items on orders.order_num = order_items.order_num
group by cust_name, orders.order_num
order by customers.cust_id,orders.order_num
– 官网答案:不包含没有下单的顾客
-- Solution using subqueries
SELECT cust_name,
order_num,
(SELECT Sum(item_price*quantity)
FROM order_items
WHERE orders.order_num=order_items.order_num) AS OrderTotal
FROM customers, orders
WHERE customers.cust_id = Orders.cust_id
ORDER BY cust_name, order_num;
-- Solution using joins, 不包含没有下单的顾客
SELECT cust_name,
orders.order_num,
Sum(item_price*quantity) AS OrderTotal
FROM customers, orders, order_items
WHERE customers.cust_id = Orders.cust_id
AND orders.order_num = order_items.order_num
GROUP BY cust_name, orders.order_num
ORDER BY cust_name, order_num;
/练习题12-5:查询最佳顾客,订单总价值>1000的顾客信息/
select order_num,sum(item_price*quantity) as order_amount
from order_items
GROUP BY order_num
HAVING order_amount>1000;
select customers.cust_id, customers.cust_name, orders.order_num, sum(item_price*quantity) as order_amount
from customers,orders,order_items
where customers.cust_id = orders.cust_id and order_items.order_num = orders.order_num
GROUP BY customers.cust_id,orders.order_num
HAVING order_amount>1000;
/嵌套查询 与 自联结 注意:许多数据库处理联结比处理子查询快的多/
/**给与Jim Jones同公司的所有顾客发礼物:
-- 自联结实现
select c1.cust_id, c1.cust_company,c1.cust_name,c2.cust_company,c2.cust_name
from customers as c1
INNER join customers as c2
ON c1.cust_company = c2.cust_company
and c2.cust_name='Jim Jones'
order by c1.cust_company;
-- 嵌套查询实现
select cust_id, cust_company,cust_name
from customers
where cust_company = (select cust_company from customers where cust_name='Jim Jones')
order by cust_name;
/** 练习题13-4: 查询每一项产品的总订单数量**/
select products.prod_id,prod_name, any_value(item_price),avg(item_price),sum(quantity) as total
from products left join order_items
on products.prod_id = order_items.prod_id
GROUP BY products.prod_id
ORDER BY products.prod_name;
/** 练习题13-5: 查询每一项产品的总订单数量**/
select vend_id, (select count(prod_id) from products where vendors.vend_id = products.vend_id)
from vendors;
SELECT Vendors.vend_id, COUNT(prod_id)
FROM Vendors
LEFT OUTER JOIN Products ON Vendors.vend_id = Products.vend_id
GROUP BY Vendors.vend_id;
创建表和数据sql
书简介
Sams Teach Yourself SQL in 10 Minutes (Fifth Edition) – Ben Forta