【SQL】复习与回顾2

【SQL】复习与回顾

第10课 分组数据

数据分组

  • 返回每个供应商提供的产品数目
select vend_id, COUNT(*) AS num_prods
FROM Products
GROUP BY vend_id;

GROUP BY 子句对每个组而不是整个结果进行聚集。

过滤分组

having和where的区别:WHERE过滤指定的是行而不是分组。WHERE过滤行,而HAVING过滤分组。

过滤分组,规定包括哪些分组,排除哪些分组。

  • 列出至少有两个订单的所有顾客(必须基于完整的分组而不是个别的行进行过滤)
SELECT cust_id, COUNT(*) AS orders
FROM Orders
GROUP BY cust_id
HAVING COUNT(*) >=2;

WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。

  • 检索具有两个以上产品且其价格大于等于4的供应商
SELECT vend_id, COUNT(*) AS num_prods
FROM Products
WHERE prob_price >= 4
GROUP BY vend_id
HAVING COUNT(*) >= 2;

where子句过滤所有prod_price至少为4的行,然后按vend_id分组数据,having子句过滤计数为2或2以上的分组。

  • 检索包含三个或更多物品的订单号和订购物品的数目,按订购物品的数目排序输出
SELECT order_num, COUNT(*) AS items
FROM OrderItems
GROUP BY order_num
HAVING COUNT(*) >= 3
ORDER BY items, order_num;


//输出
order_num     items
---------     ------
200006         3
200009         3
200007         5
200008         5

使用group by子句按照订单号(order_num列)分组数据,以便count(*)函数能够返回每个订单中的物品数目。having子句过滤数据,使得只返回包含三个或更多物品的订单。

第11课 利用子查询进行过滤

1、Vendors表包括供应商名称和地址信息;

2、Orders表包含收到的所有订单;

3、OrderItems表包含每个订单中的各项物品。

订单存储在两个表中,每个订单包括订单编号,客户iD,订单日期,在Orders表中存储为一行。

各订单的物品存储在相关的OrderItems表中。Orders表不存储顾客信息,只存储客户ID。顾客的实际信息存储在Customers表中。

  • 列出订购物品RGAN01的所有顾客

(1)检索包含物品RGAN01的所有订单的编号。

(2)检索具有前一步骤列出的订单编号的所有顾客的ID。

(3)检索前一步骤返回的所有谷歌ID的顾客信息。

//(1)
SELECT order_num
FROM OrderItems
WHERE prod_id = 'RGANO01'

order_num
----------
20007
20008



//(2)
SELECT cust_id 
FROM Orders
WHERE order_num IN (200007,20008);


cust_id
-------
100000004
100000005

//(3)
SELECT cust_name, cust_concact
FROM Customers
WHERE cust_id IN ('100000004','100000005');
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 = 'GRAN01'
));
  • 需要显示Customers表中每个顾客的订单总数。 订单与相应的顾客ID存储在Orders表中。

(1)从Customers表中检索顾客列表;

(2)对于检索出的每个顾客,统计其在Orders表中的订单数目。

如果对顾客100000001的订单进行计数

SELECT COUNT(*) AS orders
FROM Orders
WHERE cust_id = ’1000000001‘;

要对每一个顾客执行count(*),则应该作为子查询。

SELECT cust_name,cust_state,
        (SELECT COUNT(*) FROM Orders 
         WHERE Orders.cust_id = Customers.cust_id) AS orders
FROM Customers
ORDER BY cust_name;

该子查询对检索出的每个顾客执行一次。

第12课 联结表

相同的数据出现多次不是一件好事。关系表的设计就是要把信息分解成多个表,一类数据一个表。各表通过某些共同的值相互关联(所以才叫关系数据库)。

如果数据存储在多个表中,怎么样用一条select语句就检索出数据呢?使用结联。

SELECT vend_name,prod_name,prod_price
FROM Vendors,Products
WHERE Vendors.vend_id = Products.vend_id;

在联结两个表时,实际要做的是将第一表中的每一行与第二个表中的每一行配对。WHERE子句作为过滤条件,只包含那些匹配给定条件的行。

由没有联结条件的表关系返回的结果为笛卡尔积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。

内联结 

基于两个表之间的相等测试。

与上面相同

SELECT vend_name,prod_name,prod_price
FROM Vendors INNER JOIN Products
ON Vendors.vend_id = Products.vend_id;

联结多个表

  • 显示订单20007中的物品
SELECT prod_name,vend_name,prod_name,prod_price,quantity
FROM OrderItems,Vendors,Products
WHERE Vendors.vend_id = Products.vend_id
AND OrderItems.prod_id = Products.prod_id
AND order_num = 20007;

所以子查询可以用内联结代替

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 = 'GRAN01'));
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 = 'GRAN01'));

第13课 创建高级联结

使用表别名

可以给表名起别名,列名和计算字段也可以。

SELECT cust_name,cust_contact
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 = 'GRAN01'));

使用不同类型的联结

除了内联结,还有自联结,自然联结,外联结。

自联结

使用表别名的主要原因是能在一条select语句中不止一次引用相同的表。

  • 要给jim同一公司的所有顾客发送一封信件。

(1)找到jim工作的公司;

(2)找到在该公司工作的顾客。

SELECT cust_id,cust_name,cust_contact
FROM Customers
WHERE cust_name = (SELECT cust_name
                    FROM Customers
                    WHERE cust_concact = 'jim');

Customers表在from子句中出现了两次,使用自联结如下:

SELECT c1.cust_id, c1.cust_name, c1.cust_contact
FROM Customers AS c1,Customers AS c2
WHERE c1.cust_name = c2.cust_name
AND c2.cust_concact = 'jim');

自联结通常用来代替从相同表中检索数据的使用子查询语句。

自然联结

无论何时对表进行联结,应该至少有一列不止出现在一个表中。(就是被联结的那个列肯定是在两个表里都出现啦)。内联结返回所有数据,相同的列甚至多次出现。自然联结排除多次出现,使得每一列只返回一次。

自然联结要求只能选择那些唯一的列,一般通过对一个表使用通配符(SELECT *),而对其他表的列使用明确的子集来完成。

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 = 'GRAN01'));

通配符只对第一表使用,所有其他列明确列出,所以,没有重复的列被检索出来。

(不太理解。C.cust_id = O.cust_id, OI.order_num = O.order_num重复)

外联结

以上联结都是将一个表中的行与另一个表中的行相关联,但是有时候需要包含没有关联行的那些行。(我的理解是两个表里没有重复的列)

对每个顾客下的订单进行计数,包括那些至今尚未下订单的顾客;

列出所有产品以及订购数量,包括没有人订购的产品;

外联结:那些在相关表中没有关联行的行。

  • 检索所有顾客及其订单(内联结)
SELECT Customers.cust_id, Orders.order_num
FROM Customers INNER JOIN Orders
ON Customers.cust_id = Orders.cust_id;
  • 检索包括没有订单顾客在内的所有顾客(外联结)

也就是说cust_id这个顾客在Orders表中是没有数据的。

SELECT Customers.cust_id, Orders.order_num
FROM Customers LEFT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;


cust_id    order_num
-------    ----------
1000001    20005
1000001    20009
1000002    NULL    
1000003    20006
1000004    20007
1000005    20008

(right指的是outer join右边的表,left是outer join左边的表)。上面的例子是从Customers表中选择所有行。

全外联结检索两个表中的所有行并关联那些可以关联的行。即包含两个表的不关联的行。

SELECT Customers.cust_id, Orders.order_num
FROM Customers FULL OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;
  • 检索所有顾客和每个顾客所下的订单数
SELECT Customers.cust_id, 
        COUNT(Orders.order_num) AS num_ord
FROM Customers INNNER JOIN Orders
ON Customers.cust_id = Orders.cust_id
GROUP BY Customers.cust_id;


cust_id    order_num
-------    ----------
1000001    2    
1000003    1
1000004    1
1000005    1

此时看外联结的差别!使用左外部联结来包含所有顾客,甚至包含没有任何订单的顾客。

SELECT 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;


cust_id    order_num
-------    ----------
1000001    2
1000002    0    
1000003    1
1000004    1
1000005    1

第14课 组合查询

  • 需要A,B,C等几个美国州的所有顾客的报表,还行包括不管位于哪个州的所有的fun4all。
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('A','B','C')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'full4all';

多条件的where子句

SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('A','B','C')
OR cust_name = 'full4all';

使用UNION时,重复的行会被自动取消。如果想返回所有的匹配行,使用NUION ALL。

NULL值与空字符串不同。

NULL值是没有值,不是空字符串。

‘’空字符换是一个有效的值,它不是无值。

发布了316 篇原创文章 · 获赞 96 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/weixin_31866177/article/details/104865567