# 找到昵称满足的,c开头的试卷, 
# 计算按用户和试卷分组的均分

SELECT uid, exam_id, ROUND(AVG(avg_score), 0) avg_score
FROM ( # 设为子查询是因为不能在这里对其分组
SELECT uid, exam_id, 
    AVG(score) OVER(PARTITION BY uid, exam_id) avg_score
FROM exam_record a
    JOIN user_info b USING(uid)
    JOIN examination_info c USING(exam_id)
WHERE (nick_name LIKE '牛客%号' OR nick_name/2 > 0) AND (tag LIKE 'C%' OR tag LIKE 'c%')# WHERE LOWER(tag) LIKE 'c%' #使用该函数会更简洁
ORDER BY uid, avg_score
) a
GROUP BY uid, exam_id
HAVING avg_score IS NOT NULL

踩的坑:限制条件这里,最开始没有用圆括号,导致第一个or就使得第一个条件符合的就行了

在 SQL 中,ANDOR 是逻辑运算符,它们用来组合多个条件。AND 操作符表示所有条件都必须为真,才会选择记录;而 OR 操作符表示只要任一条件为真,就会选择记录。重要的是,AND 操作符的优先级高于 OR 操作符。

让我们来对比一下您给出的两个 WHERE 子句:

有括号的条件:

WHERE (nick_name LIKE '牛客%号' OR nick_name/2 > 0) AND (tag LIKE 'C%' OR tag LIKE 'c%')

  • 这个查询首先计算括号内的条件,然后使用 AND 运算符组合结果。
  • 只有当 nick_name 字段以 '牛客' 开头并以 '号' 结尾或者 nick_name/2 的结果大于 0,且同时 tag 字段以大写或小写的 'C' 开头时,记录才会被选中。

没有括号的条件:

WHERE nick_name LIKE '牛客%号' OR nick_name/2 > 0 AND tag LIKE 'C%' OR tag LIKE 'c%'

  • 在没有括号的情况下,AND 运算符将首先被计算。
  • 所以 nick_name/2 > 0 AND tag LIKE 'C%' 会首先被评估,然后结果会与其他 OR 条件组合。
  • 这可能会导致不同的结果集,因为没有明确的分组指示 SQL 如何组合这些条件。

为了更清楚地理解两者之间的区别,让我们分解第二个条件:

  1. 如果 nick_name 字段以 '牛客' 开头并以 '号' 结尾,那么记录会被选中,无论 tag 字段的值是什么。
  2. 如果 nick_name/2 的结果大于 0 且 tag 字段以大写 'C' 开头,那么记录会被选中。
  3. 如果 tag 字段以小写 'c' 开头,那么记录会被选中,无论 nick_name 的值是什么。

可以看出,没有使用括号的查询可能会因为 ORAND 的优先级问题而返回更多的记录。

通常来说,使用括号来明确指定条件的逻辑组合是一个好习惯,因为它可以避免混淆,并确保条件的执行顺序与你的意图相符。

使用窗口函数时不需要 GROUP BY:窗口函数会在保持原始行数不变的情况下为每行添加一个计算列。因此,如果您尝试在窗口函数的查询中同时使用 GROUP BY,您可能会收到一个错误,因为 GROUP BY 会尝试对结果集进行聚合。

新知识点:

1、在大多数SQL数据库中,字符串比较默认是区分大小写的。但是,你可以通过使用不区分大小写的比较来简化这个条件。根据你使用的数据库系统,有几种方法可以实现不区分大小写的搜索。

SQL标准方法

大多数数据库都支持 ILIKE 关键字,或者 LOWER() 函数来进行不区分大小写的比较:

使用 ILIKE(这通常在 PostgreSQL 中可用):

WHERE tag ILIKE 'c%'

使用 LOWER() 函数:

WHERE LOWER(tag) LIKE 'c%'

这两种方法都会找到以 'C' 或 'c' 开头的 tag 值。

MySQL

在 MySQL 中,你可以使用 COLLATE 来指定在比较时使用的字符集和校对规则,例如:

WHERE tag COLLATE utf8_general_ci LIKE 'c%'

这里 utf8_general_ci 是一个不区分大小写的校对规则,ci 表示 case-insensitive(不区分大小写)。

SQL Server

在 SQL Server 中,你需要查看列的校对顺序设置。如果它被设置为不区分大小写(例如 SQL_Latin1_General_CP1_CI_AS),你可以直接使用:

WHERE tag LIKE 'c%'

并且它会返回所有以 'C' 或 'c' 开头的 tag 值。

Oracle

在 Oracle 中,默认情况下字符串比较是区分大小写的,但你可以使用 UPPER()LOWER() 函数来进行不区分大小写的比较:

WHERE LOWER(tag) LIKE 'c%'

在编写你的查询时,请根据你所使用的数据库系统选择适当的方法。如果你不确定数据库的默认大小写敏感性或者校对规则设置,使用 LOWER()UPPER() 函数是一个可靠的选择,因为它们在所有主流数据库系统中都是可用的。

2、在 MySQL 中,要判断一个字段的值是否为纯数字,您不能直接使用 nick_name/2 > 0,因为如果 nick_name 是一个包含非数字字符的字符串,这样的除法操作会导致错误或者返回 NULL。

相反,您可以使用正则表达式来检查一个字段是否只包含数字。在 MySQL 中,您可以使用 REGEXP 来进行正则匹配:

SELECT * FROM table_name WHERE column_name REGEXP '^[0-9]+$';

这条 SQL 语句会选择 column_name 字段中只包含数字的所有记录。这里的正则表达式 '^[0-9]+$' 的含义是:

  • ^:匹配字符串的开始
  • [0-9]+:匹配一个或多个数字
  • $:匹配字符串的结束

结合在一起,这个正则表达式匹配从开始到结束的整个字符串,确保字符串中没有其他字符,只有数字。

在 MySQL 8.0+ 中,您也可以使用 RLIKE,它是 REGEXP 的同义词:

SELECT * FROM table_name WHERE column_name RLIKE '^[0-9]+$';

如果您使用的是早期版本的 MySQL,您可能需要使用不同的正则表达式语法或函数。请根据您的 MySQL 版本进行调整。