SQL 练习

SQL 练习

SQL一直不是很好,在做了一些练习后将一些有价值的记录下来

SQL 模版:

SELECT column, another_column,FROM mytable
WHERE condition(s)
ORDER BY column ASC/DESC
LIMIT num_limit OFFSET num_offset;

INNER JOIN:C=A∩B 取交集

SELECT column, another_table_column,FROM mytable (主表)
INNER JOIN another_table (要连接的表)
    ON mytable.id = another_table.id (想象一下刚才讲的主键连接,两个相同的连成1)
WHERE condition(s)
ORDER BY column,ASC/DESC
LIMIT num_limit OFFSET num_offset;

LEFT JOIN, RIGHT JOIN, FULL JOIN和 INNER JOIN 的语法一样,区别在原理:左连接保留 A 的所有行,右连接则保留 B 的所有行,全连接则不管有没有匹配上,同时保留两者。

JOIN 优化:分为两种情况:数据规模小和数据规模大的情况,数据规模小就直接放入内存连接,数据规模大的可以通过**增加索引(最有效直接)**来优化join 语句的执行速度,可以通过缓存来减少join 的次数,尽量减少表连接的次数,一个 SQL 语句表连接的次数不应超过 5 次;在执行 join 语句的时候必然要有一个比较的过程,所以尽量将其放到内存块中来提高执行效率,以 MySQL 的 innodb 为例,可以通过调节它的内存区域:show variables like '%buffer%'可以找到一个 join_buffer_size 的变量名,它的大小决定了我们 join 语句的性能。但是有个大前提,任何项目终究要上线,而产生的数据规模不会小,大部分数据最终要保存到硬盘上,以文件的形式存储。有索引的话直接读取索引树就可以很快,而没有的话现在一般采用 block 块比较,就是取一块到内存中进行比较;

HAVING:可以对分组之后的数据再做 SELECT 查询。having 和 where 的语法一样,只不过作用的结果集不一样。在大数据时很有用。

【难题】找到还没有雇员的办公室
SELECT b.building_name FROM buildings b
left join employees e
on e.building=b.building_name 
where e.building is null;

【难题】John Lasseter导演的每部电影每分钟值多少钱,告诉我最高的3个电影名和价值就可以 ✓
SELECT title, (domestic_sales+international_sales)/length_minutes as sale_value FROM movies m,boxoffice b
where director="John Lasseter" and m.id = b.movie_id 
order by (domestic_sales+international_sales)/length_minutes desc
limit 3;

【难题】每栋办公室按人数排名,不要统计无办公室的雇员
SELECT building, count(building) count FROM employees 
where building is not null group by building ;

【难题】按角色分组算出每个角色按有办公室和没办公室的统计人数(列出角色,数量,有无办公室,注意一个角色如果部分有办公室,部分没有需分开统计) ✓
SELECT count(name) count,role,
case when building is not null then '1' else '0' end as bn
FROM employees  
group by role ,bn ;

这才是完整的SELECT查询
SELECT DISTINCT column, AGG_FUNC(column_or_expression),FROM mytable
    JOIN another_table
      ON mytable.column = another_table.column
    WHERE constraint_expression
    GROUP BY column
    HAVING constraint_expression
    ORDER BY column ASC/DESC
    LIMIT count OFFSET COUNT;
  
【难题】按导演分组计算销售总额,求出平均销售额冠军(统计结果过滤掉只有单部电影的导演,列出导演名,总销量,电影数量,平均销量)SELECT director,sum(domestic_sales+international_sales) sum_sale,
count(id),
sum(domestic_sales+international_sales)/count(id) avg_sale FROM movies m
left join boxoffice b
on m.id = b.movie_id
group by director
having count(id) > 1
order by avg_sale desc
limit 1;

【变态难】找出每部电影和单部电影销售冠军之间的销售差,列出电影名,销售额差额
SELECT Title, (SELECT MAX(Domestic_sales+International_sales) 
FROM Boxoffice) - SUM(Domestic_sales+International_sales) 
AS Diff FROM Movies INNER JOIN Boxoffice 
ON Movies.ID = Boxoffice.Movie_id 
GROUP BY Title; 

# sqlzoo

# 找出所有國家,其名字以 C 作開始,ia 作結尾。
SELECT name FROM world
  WHERE name LIKE 'C%%ia'
# 找出所有國家,其名字包括三個或以上的a。
SELECT name FROM world where name like '%a%a%a%'
# 找出所有國家,其名字以t作第二個字母。
SELECT name FROM world WHERE name LIKE '_t%' ORDER BY name
# 找出所有國家,其名字都是 4 個字母的。
SELECT name FROM world WHERE name LIKE '____'
# 顯示所有國家名字,其首都是國家名字加上”City”。
SELECT name FROM world WHERE  capital = concat(name,' City')
# 找出所有首都和其國家名字,而首都要有國家名字中出現。
select capital, name from world where capital like concat('%',name,'%')
# 找出所有首都和其國家名字,而首都是國家名字的延伸。你应显示 Mexico City,因它比其國家名字 Mexico 長。你不应显示 Luxembourg,因它的首都和國家名相是相同的
select name ,capital from world where capital like concat('%',name,'_%') 

#  列出1984年的获奖者名字和奖项,按奖项和获奖者名字排序,化学奖和物理学奖放在最后;
SELECT winner, subject
  FROM nobel
 WHERE yr=1984
 ORDER BY subject IN ('physics','chemistry'),subject,winner -- 表达式subject IN ('physics','chemistry')可以作值:0 或 1

ALL 运算符是一个逻辑运算符,它将单个值与子查询返回的单列值集进行比较,ALL 和 ANY 用法类似。语法:where 列名 比较符 ALL(子查询)

条件描述
C > ALL(…)c 列中的值必须大于要评估为 true 的集合中的最大值
C >= ALL(…)c 列中的值必须大于等于评估为 true 的集合中的最大值
C < ALL(…)c 列中的值必须小于要评估为 true 的集合中的最小值
C <= ALL(…)c 列中的值必须小于等于要评估为 true 的集合中的最小值
C <> ALL(…)c 列中的值不得等于要评估为 true 的集合中的任何值
C = ALL(…)c 列中的值必须要等于要评估为 true 的集合中的任何值
# 查找世界上最大的国家(以人口计算)
SELECT name
  FROM world
 WHERE population >= ALL(SELECT population
                           FROM world
                          WHERE population>0)
                          
# 找出比欧洲所有的国家 GDP 都高的国家
select name from world 
where gdp > ALL(select gdp from world where continent = 'Europe' and gdp > 0)
# 在每一个洲中找出面积最大的国家
select name,continent,area from world x
	where area >= ALL(select area from world y where x.continent = y.continent and area > 0)
# 列出洲份名稱,和每個洲份中國家名字按子母順序是排首位的國家名。(即每洲只有列一國)
select continent,name from world x 
where name <= ALL(select name from world y where x.continent= y.continent)
# 找出洲份,其中全部国家都有不大于25000000的人口,在这些洲份中列出国家名称、洲份和人口
SELECT name, continent, population
  FROM world 
WHERE continent IN (SELECT DISTINCT continent FROM world x
                     WHERE 25000000 >= (SELECT MAX(population) FROM world y
                                        WHERE x.continent = y.continent));
# 有些国家的人口是同洲份的所有其他国家的3倍或以上。列出这些国家的名称和洲份
select name,continent from world x 
where x.population/3 >=  ALL(select population from world y where x.name != y.name and population > 0 and x.continent=y.continent)

COALESCE, CASE 和 IFNULL

# COALESCE:要替换结果集中的 null 值
SELECT 
    customerName, city, COALESCE(state, 'N/A'), -- 如果state值为null,则将其替换为'N/A'
    country
FROM
    customers;

SELECT 
    id, title, COALESCE(excerpt, LEFT(body, 150)),-- 当excerpt值为null时,将另一列(body)的值取前150个字符替换
    published_at
FROM
    articles;

# IFNULL 函数只能接受两个参数,如果不为null返回第一个参数,否则返回第二个;而 COALESE 则可以为n个,根据条件返回第一个非null值,如果参数都为null,则返回null

# CASE 和 COLESCE 相比可以实现相同功能,只是代码更多
select t.name,case when t.dept ='1' or t.dept = '2' then 'Sci'
                   when t.dept='3' then 'Art'
                   else 'None' end
 from teacher t 

显示从Craiglockhart 到 Haymarket 的选择:

SELECT DISTINCT a.name, b.name
  FROM stops a JOIN route z ON a.id=z.stop
  JOIN route y ON y.num = z.num
  JOIN stops b ON y.stop=b.id
 WHERE a.name='Craiglockhart' AND b.name ='Haymarket'
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值