select
1 2 3 4 5 6 7 SELECT product_id FROM products WHERE low_fats = 'Y' AND recyclable = 'Y'
1 2 3 4 5 6 7 SELECT name FROM Customer WHERE referee_id != 2 or referee_id is NULL
1 2 3 4 5 6 7 8 9 SELECT name, population, area FROM World WHERE area >= 3000000 OR population >= 25000000
1 2 3 4 5 6 7 8 SELECT DISTINCT author_id AS id FROM Views WHERE author_id = viewer_id ORDER BY id ASC
1 2 3 4 5 6 SELECT tweet_id FROM Tweets WHERE LENGTH(content) > 15
Basic Joins
内连接(Inner Join):
内连接用于将两个或多个表中满足连接条件的行合并在一起,只返回那些在连接条件下匹配的行。最常见的内连接类型是等值连接,但也可以进行非等值连接。
等值连接(Equi Join): 等值连接是内连接的一种,它基于两个表之间的相等条件连接这些表。例如,如果你有一个包含顾客信息的表和一个包含订单信息的表,并且想要获取每个订单对应的顾客信息,你可以使用等值连接来基于顾客ID等条件连接这两个表。
非等值连接(Non-Equi Join): 非等值连接也是内连接的一种,不仅基于相等条件,还可以使用其他比较操作符(如大于、小于等)来连接表。例如,你可以使用非等值连接来查找价格高于平均价格的产品,连接条件可能是产品价格大于平均价格。
自连接(Self Join): 自连接是一种特殊的内连接,它用于将表与自身连接。这在表中包含层次结构或需要比较不同行之间的数据时非常有用。例如,如果你有一个包含员工信息的表,你可以使用自连接来找出员工之间的经理关系。
外连接(Outer Join):
外连接用于联接两个表,并返回一个结果集,包括了匹配条件下的行以及未匹配条件下的行。外连接有三种类型:
左连接(Left Join): 左连接返回左表中的所有行,以及右表中与左表匹配的行。如果没有匹配的行,右表中的列将包含 NULL 值。左连接通常用于保留左表的所有数据,而只获取与之关联的右表数据。
右连接(Right Join): 右连接与左连接相反,它返回右表中的所有行,以及左表中与右表匹配的行。如果没有匹配的行,左表中的列将包含 NULL 值。右连接通常用于保留右表的所有数据,而只获取与之关联的左表数据。
全外连接(Full Outer Join): 全外连接返回左表和右表中的所有行,并将不匹配的行用 NULL 值填充。这意味着无论是左表中没有匹配的行,还是右表中没有匹配的行,都会包含在结果集中。
交叉连接(Cross Join):
交叉连接是一种特殊的连接,它将一个表的每一行与另一个表的每一行进行组合,从而生成一个笛卡尔积。交叉连接通常用于获取所有可能的组合,但在大多数情况下会生成非常大的结果集,因此需要谨慎使用。
1 2 3 4 5 6 SELECT EmployeeUNI.unique_id, Employees.name FROM Employees LEFT JOIN EmployeeUNI ON Employees.id = EmployeeUNI.id
1 2 3 4 5 6 7 SELECT product_name, year , price FROM Product p RIGHT JOIN Sales s ON p.product_id = s.product_id
或者使用左连接
1 2 3 4 5 6 7 SELECT product_name, year , price FROM Sales s LEFT JOIN Product p ON p.product_id = s.product_id
或者使用内连接
A INNER JOIN B
,在A中也有,在B中也有的数据才能查询出来。INNER
可省。
1 2 3 4 5 6 7 SELECT product_name, year , price FROM Product p Join Sales s ON p.product_id = s.product_id
1 2 3 4 5 6 7 8 9 10 SELECT customer_id, COUNT (customer_id) AS count_no_trans FROM Visits v LEFT JOIN Transactions t ON v.visit_id = t.visit_id WHERE transaction_id IS NULL GROUP BY customer_id
1 2 3 4 5 6 SELECT w2.id FROM Weather w1 JOIN Weather w2 ON DATEDIFF(w1.recordDate, w2.recordDate) = -1 AND w1.temperature < w2.temperature
或者使用等值连接
1 2 3 4 5 6 7 8 SELECT w2.id FROM Weather w1, Weather w2 WHERE DATEDIFF(w1.recordDate, w2.recordDate) = -1 AND w1.temperature < w2.temperature
1 2 3 4 5 6 7 8 9 10 11 12 13 14 SELECT a1.machine_id, round( avg (a2.timestamp - a1.timestamp), 3 ) AS processing_time FROM Activity a1 JOIN Activity a2 ON a1.machine_id = a2.machine_id AND a1.process_id = a2.process_id AND a1.activity_type = 'start' AND a2.activity_type = 'end' GROUP BY a1.machine_id
1 2 3 4 5 6 7 8 9 SELECT e.name, b.bonus FROM Bonus b RIGHT JOIN Employee e ON e.empId = b.empId WHERE b.bonus < 1000 OR b.bonus IS NULL
思考 为什么用了右连接,还要再加b.bonus IS NULL
非空条件?
因为,除了ON的连接条件,后面又加了WHERE筛选bonus小于1000的情况,这样如果不添加该条件,没有奖金的员工将无法返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 SELECT stu.student_id, stu.student_name, sub.subject_name, COUNT (exam.subject_name) AS attended_exams FROM Students stu CROSS JOIN Subjects sub LEFT JOIN Examinations exam ON stu.student_id = exam.student_id AND sub.subject_name = exam.subject_name GROUP BY sub.subject_name, stu.student_id ORDER BY stu.student_id, sub.subject_name
思考 为什么分组条件不是exam.subject_name,exam.student_id
?
因为Examinations表中可能不会一一对应Subjects表中的课程和Students表中的学生id号,这样会导致,如果学生没有参加任何考试,该分组条件对于这样的学生无效;
或者使用子查寻,先搜索出Examination中的部分,作为结果exam左连接至Students表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 SELECT stu.student_id, stu.student_name, sub.subject_name, COALESCE (exam.attended_exams, 0 ) AS attended_exams FROM Students stu CROSS JOIN Subjects sub LEFT JOIN ( SELECT student_id, subject_name, COUNT (* ) AS attended_exams FROM Examinations GROUP BY subject_name, student_id ) exam ON stu.student_id = exam.student_id AND sub.subject_name = exam.subject_name ORDER BY stu.student_id, sub.subject_name
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 SELECT e1.name FROM Employee e1 JOIN Employee e2 ON e2.managerId = e1.id GROUP BY e2.managerId HAVING COUNT (e2.id) >= 5
注意 名字不是唯一的,只有工号才是主键,是唯一的。不可以为了让名字匹配不重复而使用DISTINCT(e1.name)
,应当按照e2.managerId
进行分组。