二、MySQL 的 SQL 语句

159 阅读7分钟

连表查询

举例说明:

Employees表

idname
1Alice
7Bob
11Meir
90Winston
3Jonathan

EmployeeUNI表

idunique_id
31
112
903

我们需要查询这两张表,关联的字段是id,我希望能够查询出name对应的unique_id,如果没有,就输出 null

这里需要使用left joinon将两张表进行组合,组合后的表为:

idnameidunique_id
1Alicenullnull
7Bobnullnull
11Meir112
90Winston903
3Jonathan31

SQL语句:

SELECT 
    EmployeeUNI.unique_id, Employees.name
FROM
    Employees 
LEFT JOIN 
    EmployeeUNI 
ON 
    Employees.id = EmployeeUNI.id;

ONWHERESQL 中都用于设置条件,但它们在连接(JOIN)操作中的作用是不同的。

  1. ON:在 JOIN 操作中,ON 关键字用于设置连接条件。例如,在你的查询中,ON Employees.id=EmployeeUNI.id 是连接 Employees 表和 EmployeeUNI 表的条件,即只有当两个表中的 id 相等时,才会将这两个表的行连接在一起。
  2. WHERE:WHERE 关键字用于过滤结果集,即只返回满足特定条件的行。如果你在查询中使用 WHERE Employees.id=EmployeeUNI.id,那么只有当 Employees 表和 EmployeeUNI 表中的 id 相等时,才会在结果集中返回这些行。

总的来说,ON 关键字定义了如何连接两个表,而 WHERE 关键字定义了如何过滤这些连接后的结果。在某些情况下,使用 ONWHERE 可能会得到相同的结果,但在其他情况下,结果可能会有所不同,特别是在执行外连接(如 LEFT JOIN RIGHT JOIN)时。

  • 内连接(INNER JOIN)只返回两个表中都有匹配的行。
  • 左连接(LEFT JOIN)返回左表(这里是 Employees表)的所有行,如果右表(这里是 EmployeeUNI 表)中没有匹配的行,则结果集中的对应列将为 NULL
  • WHERE 子句返回满足特定条件的行,这里的条件是 Employees.id 等于 EmployeeUNI.id

自连接问题

Weather 表:

idrecordDatetemperature
12015-01-0110
22015-01-0225
32015-01-0320
42015-01-0430

需要找到当前日期比前一天的温度高的数据。也就是id2、4的情况。

想要查询这种情况,就需要进行表的自连接,也就是说,把这张表当成两张表看,然后进行连接,此时就会产生n*n条数据:

idrecordDatetemperatureidrecordDatetemperature
42015-01-043012015-01-0110
32015-01-032012015-01-0110
22015-01-022512015-01-0110
12015-01-011012015-01-0110
42015-01-043022015-01-0225
32015-01-032022015-01-0225
22015-01-022522015-01-0225
12015-01-011022015-01-0225
42015-01-043032015-01-0320
32015-01-032032015-01-0320
22015-01-022532015-01-0320
12015-01-011032015-01-0320
42015-01-043042015-01-0430
32015-01-032042015-01-0430
22015-01-022542015-01-0430
12015-01-011042015-01-0430

然后通过DATEDIFF(date1,date2)来进行判断,如果结果为1表示date1date2大一天,如果为-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问题

在传统的布尔逻辑中,只有TRUEFALSE两种值。

但在数据库中,特别是在处理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

这里看到有个评论提到了orunion的区别,我去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中遇到的一部分问题,后期边学边整理一下。