连表查询
举例说明:
Employees表:
| id | name |
|---|---|
| 1 | Alice |
| 7 | Bob |
| 11 | Meir |
| 90 | Winston |
| 3 | Jonathan |
EmployeeUNI表:
| id | unique_id |
|---|---|
| 3 | 1 |
| 11 | 2 |
| 90 | 3 |
我们需要查询这两张表,关联的字段是id,我希望能够查询出name对应的unique_id,如果没有,就输出 null。
这里需要使用left join和on将两张表进行组合,组合后的表为:
| id | name | id | unique_id |
|---|---|---|---|
| 1 | Alice | null | null |
| 7 | Bob | null | null |
| 11 | Meir | 11 | 2 |
| 90 | Winston | 90 | 3 |
| 3 | Jonathan | 3 | 1 |
SQL语句:
SELECT
EmployeeUNI.unique_id, Employees.name
FROM
Employees
LEFT JOIN
EmployeeUNI
ON
Employees.id = EmployeeUNI.id;
ON 和 WHERE 在 SQL 中都用于设置条件,但它们在连接(JOIN)操作中的作用是不同的。
ON:在JOIN操作中,ON关键字用于设置连接条件。例如,在你的查询中,ONEmployees.id=EmployeeUNI.id是连接Employees表和EmployeeUNI表的条件,即只有当两个表中的id相等时,才会将这两个表的行连接在一起。WHERE:WHERE关键字用于过滤结果集,即只返回满足特定条件的行。如果你在查询中使用WHEREEmployees.id=EmployeeUNI.id,那么只有当Employees表和EmployeeUNI表中的id相等时,才会在结果集中返回这些行。
总的来说,ON 关键字定义了如何连接两个表,而 WHERE 关键字定义了如何过滤这些连接后的结果。在某些情况下,使用 ON 和 WHERE 可能会得到相同的结果,但在其他情况下,结果可能会有所不同,特别是在执行外连接(如 LEFT JOIN 或 RIGHT JOIN)时。
- 内连接(
INNER JOIN)只返回两个表中都有匹配的行。 - 左连接(
LEFT JOIN)返回左表(这里是Employees表)的所有行,如果右表(这里是EmployeeUNI表)中没有匹配的行,则结果集中的对应列将为NULL。 WHERE子句返回满足特定条件的行,这里的条件是Employees.id等于EmployeeUNI.id。
自连接问题
Weather 表:
| id | recordDate | temperature |
|---|---|---|
| 1 | 2015-01-01 | 10 |
| 2 | 2015-01-02 | 25 |
| 3 | 2015-01-03 | 20 |
| 4 | 2015-01-04 | 30 |
需要找到当前日期比前一天的温度高的数据。也就是id为2、4的情况。
想要查询这种情况,就需要进行表的自连接,也就是说,把这张表当成两张表看,然后进行连接,此时就会产生n*n条数据:
| id | recordDate | temperature | id | recordDate | temperature |
|---|---|---|---|---|---|
| 4 | 2015-01-04 | 30 | 1 | 2015-01-01 | 10 |
| 3 | 2015-01-03 | 20 | 1 | 2015-01-01 | 10 |
| 2 | 2015-01-02 | 25 | 1 | 2015-01-01 | 10 |
| 1 | 2015-01-01 | 10 | 1 | 2015-01-01 | 10 |
| 4 | 2015-01-04 | 30 | 2 | 2015-01-02 | 25 |
| 3 | 2015-01-03 | 20 | 2 | 2015-01-02 | 25 |
| 2 | 2015-01-02 | 25 | 2 | 2015-01-02 | 25 |
| 1 | 2015-01-01 | 10 | 2 | 2015-01-02 | 25 |
| 4 | 2015-01-04 | 30 | 3 | 2015-01-03 | 20 |
| 3 | 2015-01-03 | 20 | 3 | 2015-01-03 | 20 |
| 2 | 2015-01-02 | 25 | 3 | 2015-01-03 | 20 |
| 1 | 2015-01-01 | 10 | 3 | 2015-01-03 | 20 |
| 4 | 2015-01-04 | 30 | 4 | 2015-01-04 | 30 |
| 3 | 2015-01-03 | 20 | 4 | 2015-01-04 | 30 |
| 2 | 2015-01-02 | 25 | 4 | 2015-01-04 | 30 |
| 1 | 2015-01-01 | 10 | 4 | 2015-01-04 | 30 |
然后通过DATEDIFF(date1,date2)来进行判断,如果结果为1表示date1比date2大一天,如果为-1表示小一天。
select a.id from Weather a join Weather b on datediff(a.recordDate,b.recordDate) =1
where a.temperature > b.temperature;
SQL自带字符串处理函数
MySQL提供了多种文本函数,用于处理字符串和文本数据。以下是一些常用的文本函数:
- CONCAT() - 将多个字符串连接成一个字符串。
- CONCAT_WS() - 使用指定的分隔符连接多个字符串。
- LENGTH() - 返回字符串的长度(以字节为单位,一个汉字是两个字节或三个字节)。
- CHAR_LENGTH() - 返回字符串的长度(以字符为单位,无论汉字还是字母都是一个字符)。
- SUBSTRING() - 从字符串中提取子字符串。
- LEFT() - 返回字符串左侧的字符。
- RIGHT() - 返回字符串右侧的字符。
- TRIM() - 移除字符串两端的空格或其他指定字符。
- LTRIM() - 移除字符串左侧的空格或其他指定字符。
- RTRIM() - 移除字符串右侧的空格或其他指定字符。
- REPLACE() - 将字符串中的某些字符替换成其他字符。
- INSERT() - 将字符串插入到另一个字符串的指定位置。
- UCASE() / UPPER() - 将字符串转换为大写。
- LCASE() / LOWER() - 将字符串转换为小写。
- REVERSE() - 反转字符串的字符顺序。
- FORMAT() - 格式化数字字符串,通常用于货币格式。
- LPAD() - 在字符串左侧填充指定数量的字符。
- RPAD() - 在字符串右侧填充指定数量的字符。
- SPACE() - 生成指定数量的空格。
- STRCMP() - 比较两个字符串,返回-1、0或1。
- SUBSTRING_INDEX() - 在字符串中查找指定分隔符的索引。
- LOCATE() / POSITION() - 在字符串中查找子字符串的位置。
- ELT() - 从字符串列表中选择一个字符串。
- FIELD() - 在字符串列表中查找字符串的位置。
- MAKE_SET() - 根据位值创建一个由字符串组成的集合。 这些函数可以在SELECT语句、WHERE子句、
- ORDER BY子句等多种场景中使用,以帮助您处理和操作数据库中的文本数据。
NULL问题
在传统的布尔逻辑中,只有TRUE和FALSE两种值。
但在数据库中,特别是在处理NULL时,需要引入第三种逻辑值:UNKNOWN。这是因为与NULL进行比较时,我们无法确定其结果,因此结果被定义为UNKNOWN。
例如,如果我们尝试比较一个NULL值和一个非NULL值,结果将是UNKNOWN,因为NULL没有一个明确的数值或状态。同样,如果我们尝试比较两个NULL值,结果也是UNKNOWN,因为我们无法确定它们之间的关系。
为了解决这个问题,MySQL提供了IS NULL和IS NOT NULL这两个操作符,它们专门用于检查字段是否为NULL。当我们使用IS NULL时,如果字段的值为NULL,查询将返回TRUE;如果字段的值不是NULL(包括字段中有值和字段为空),查询将返回FALSE。 同样地,IS NOT NULL用于检查字段值是否不是NULL
| id | name | referee_id |
| -- | ---- | ---------- |
| 1 | Will | null |
| 2 | Jane | null |
| 3 | Alex | 2 |
| 4 | Bill | null |
| 5 | Zack | 1 |
| 6 | Mark | 2 |
SELECT name from Customer where referee_id != 2 OR referee_id is null;
对于上面的数据,如果不加上is null判断函数,那么所有为null的同样不会被筛选到。
OR and UNION
这里看到有个评论提到了or和union的区别,我去stackoverflow上面查了一下,具体链接放在末尾。大致意思是:
对于单列来说,用or是没有任何问题的,但是or涉及到多个列的时候,每次select只能选取一个index,如果选择了area,population就需要进行table-scan,即全部扫描一遍,但是使用union就可以解决这个问题,分别使用area和population上面的index进行查询。 但是这里还会有一个问题就是,UNION会对结果进行排序去重,可能会降低一些performance(这有可能是方法一比方法二快的原因),所以最佳的选择应该是两种方法都进行尝试比较。 (stackoverflow链接: stackoverflow.com/questions/1…
select name, population, area from world where population >= 25000000 or area >= 3000000;
select name, population, area from world where population >= 25000000
union
select name, population, area from world where area >= 3000000;
分析:哪种情况更快还得看实际运行效果。
记录在学习SQL中遇到的一部分问题,后期边学边整理一下。