MySQL学习记录5、6-编写复杂查询&数值函数

学习内容来自B站SQL进阶教程 | 史上最易懂SQL教程!10小时零基础成长SQL大师!!

5.编写复杂查询

1.子查询

-- 选择工资在平均工资以上的员工
SELECT *
FROM employees
WHERE salary > (
	SELECT AVG(salary)
    FROM employees
);

2.IN 运算符

-- 找到所有没有开发票的客户,客户开的发票在invoices表中
SELECT *
FROM clients
WHERE client_id NOT IN (
	SELECT DISTINCT client_id
    FROM invoices
);

3.子查询VS连接

-- 找到订购了product_id = 3的产品的顾客的部分信息
-- 子查询方式
SELECT 
	c.customer_id,
    c.first_name,
    c.last_name
FROM customers c
WHERE c.customer_id IN
(
	SELECT DISTINCT customer_id
    FROM orders
    WHERE order_id IN (
		SELECT DISTINCT order_id
        FROM order_items
		WHERE product_id = 3
    )
);
-- 使用连接的方式
SELECT 
	DISTINCT c.customer_id,
    c.first_name,
    c.last_name
FROM customers c
JOIN orders o USING(customer_id)
JOIN order_items oi USING(order_id)
WHERE oi.product_id = 3;

4.ALL 关键字

-- 找出所有大于客户id为3的所有的invoice_total的发票信息
-- 等同于找出大于客户id为3的最大invoice_total的所有发票
SELECT *
FROM invoices
WHERE invoice_total > ALL(
	SELECT invoice_total
    FROM invoices
    WHERE client_id = 3
);

5.ANY 关键字

-- 找到所有开的发票数大于大于2的客户
-- =ANY 与 IN 意义相同
SELECT *
FROM clients
WHERE client_id = ANY(
	SELECT client_id
    FROM invoices
    GROUP BY client_id
    HAVING COUNT(*) >= 2
);

6.相关子查询

-- 内部查询和外部查询产生了关系,即为相关子查询,之前学的都是非相关子查询
-- 本题获取所有客户高于该客户的发票平均值的所有发票
SELECT *
FROM invoices i
WHERE invoice_total > (
	SELECT AVG(invoice_total)
    FROM invoices
    WHERE client_id = i.client_id
);

7.EXISTS 运算符

-- 不同于IN,EXISTS并不会返回一个结果集,而是在找到一个满足条件的则返回一个
-- 找到从来没有被订购过的产品信息
SELECT *
FROM products p
WHERE NOT EXISTS (
	SELECT *
    FROM order_items oi
    WHERE oi.product_id = p.product_id
)

8.SELECT 语句中的子查询

-- 不能直接在SELECT 后面跟AVG(invoice_total) AS ....因为这样后面不能使用引用
-- 最后一个不能直接用invoice_average,因为这列并不在invoices里面,而是刚刚产生的,子查询可以调用刚刚建立的列。1SELECT 
	invoice_id,
    invoice_total,
    (
		SELECT AVG(invoice_total)
        FROM invoices
    ) AS invoice_average,
    invoice_total - (SELECT invoice_average) AS differens
FROM invoices;

-- (2)较复杂,在SELECT中使用了相关子查询,连接使用了左连接,保证输出所有客户2SELECT 
	c.client_id,
    c.name,
    (
		SELECT SUM(invoice_total) FROM invoices
        WHERE i.client_id = client_id
    ) AS total_sales,
    (
		SELECT AVG(invoice_total)
        FROM invoices
    ) AS average,
    (SELECT total_sales) - (SELECT average) AS difference
FROM clients c
LEFT JOIN invoices i USING(client_id)
GROUP BY (c.client_id)

9.FROM中的子查询

-- 将8中(2)作为FROM后面的虚拟表
-- 更好的方法是将其作为视图使用
SELECT *
FROM (
	SELECT 
		c.client_id,
		c.name,
		(
			SELECT SUM(invoice_total) FROM invoices
			WHERE i.client_id = client_id
		) AS total_sales,
		(
			SELECT AVG(invoice_total)
			FROM invoices
		) AS average,
		(SELECT total_sales) - (SELECT average) AS difference
	FROM clients c
	LEFT JOIN invoices i USING(client_id)
	GROUP BY (c.client_id)
) AS sale_summary
WHERE total_sales IS NOT NULL;

6.数值函数

1.数值函数

1-- 指定四舍五入精度,下面为5.7,不指定则为整数
SELECT ROUND(5.731)2-- 截断,不四舍五入
SELECT TRUNCATE(3.3366,2);3-- 返回大于等于该数字的最小整数
SELECT CEILING(3.3366);4-- 返回小于等于该数字的最大整数
SELECT FLOOR(3.3366);5-- 计算绝对值
SELECT ABS(-3.3366)6-- 生成0-1区间的随机浮点数
SELECT RAND()

2.字符串函数

1-- 得到字符串中的字符数
SELECT LENGTH('123')2-- 字符串转换为大写
SELECT UPPER('abc')3-- 字符串转换为小写
SELECT LOWER('ABC')4-- LTRIM 删除字符串左边的空格
SELECT LTRIM('   1 23  ')5-- RTRIM 删除字符串右边的空格
SELECT RTRIM('   1 23  ')6-- TRIM 删除字符串两边的空格
SELECT TRIM('   1 23  ')7-- LEFT获得字符串左边的3个字符
SELECT LEFT('12345',3)8-- RIGHT获得字符串右边的3个字符
SELECT RIGHT('12345',3)9-- SUBSTRING 从第3个位置截取4个字符
-- 最后一个参数如果不写,则从起始位置截取到末尾
SELECT SUBSTRING('12345678',3,4)10-- LOCATE 返回一个字符或一串字符匹配的位置(不区分大小写,未找到返回0)
-- 返回3
SELECT LOCATE('34','12345678')11-- REPLACE 将字符串中的‘12’替换为‘34’
SELECT REPLACE('12345678','12','34')12-- CONCAT 合并字符串SELECT CONCAT('12345678','12','23','3')SELECT CONCAT(first_name,' ',last_name) AS full_name
FROM customers;

3.日期函数

1-- 当前的时间(日期+时间)
SELECT NOW()2-- 分别返回当前的日期和时间
SELECT 
CURDATE(),
CURTIME()3-- 返回当前的年份
SELECT 
YEAR(CURTIME()),
YEAR(NOW()),
YEAR(CURDATE())4-- 返回当前的月份
SELECT 
MONTH(CURTIME()),
MONTH(NOW()),
MONTH(CURDATE())5-- 返回当前是多少日
SELECT 
DAY(CURTIME()),
DAY(NOW()),
DAY(CURDATE())6-- 返回当前的小时 HOUR
-- 返回当前的分钟 MINUTE
-- 返回当前的秒 SECOND
-- 返回当前的字符串格式的星期数 DAYNAME
-- 返回当前的字符串格式的月份 MONTHNAME
-- 用法和前面相同7-- EXTRACT 获取相应的日期格式(标准SQL提供的一部分)
-- 如获取当前年
SELECT EXTRACT(YEAR FROM NOW())8-- 获取今年的订单
SELECT *
FROM orders
WHERE YEAR(order_date) = YEAR(NOW());

4.格式化日期和时间

1-- DATE_FORMAT格式化日期
-- %y表示两位数年份,%Y表示四位数年份
-- %m表示两位数月份,%M表示月份名称
-- %d表示两位数日,%D表示第几日如12th
-- 下面返回当前年月日,如2021年05月12日
SELECT DATE_FORMAT(NOW(),'%Y年%m月%d日')2-- TIME_FORMAT格式化时间
-- %H代表小时,%i代表分钟数,%s代表秒数
--%p代表pm/am
-- 下面返回 23时35分35秒
SELECT TIME_FORMAT(NOW(),'%H时%i分%s秒')

5.计算日期和时间

1-- 给当前天数加一天(加一年将DAY换成YEAR即可)
  -- 传负值相当于减到一个过去的时间 或使用DATE_SUB
SELECT DATE_ADD(NOW(),INTERVAL 1 DAY)2-- DATEDIFF 计算日期差
--如下面返回-1,第一个减去第二个
SELECT DATEDIFF('2021-01-15','2021-01-16')3-- TIME_TO_SEC返回从0点计数的秒数
SELECT TIME_TO_SEC('09:00')

6.IFNULL 和COALESCE 函数

1-- 将orders表中的shipper_id为空的值替换为后面的字符串
SELECT 
	order_id,
    IFNULL(shipper_id,'Not assigned')
FROM orders
(2-- 如果shipper_id为空,则返回comments对应的值,如果都为空,返回后面的值
SELECT 
	order_id,
    COALESCE(shipper_id,comments,'Not assigned')
FROM orders

7.IF函数

-- 如果第一个条件满足,返回第二个参数,否则返回第三个参数
SELECT 
	product_id,
    name,
    COUNT(*) AS orders,
    IF(COUNT(*) > 1,'Many times','Once') AS frequency
FROM order_items
JOIN products USING(product_id)
GROUP BY product_id

在这里插入图片描述

8.CASE运算符

-- IF语句只能返回一个判断式,而CASE可以返回多个
-- 格式为 CASE WHEN THEN ... 最后可以加个ELSE,最后END
SELECT 
	CONCAT(first_name,' ',last_name) AS customer,
    points,
    CASE 
		WHEN points < 2000 THEN 'Bronze'
        WHEN points BETWEEN 2000 AND 3000 THEN 'Silver'
        ELSE 'Gold'
	END AS category
FROM customers
ORDER BY points DESC;

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值