一、简答题
1、SQL中常用的统计函数
- count(列名): 统计表中指定列的非空值数量
- count(列名):只包括列名对应一列,不包括null值或空值
- count(distinct 列名):只包括列名对应一列,不包括null值或空值,去重
- count(*):统计所有行数,无论列值是否为null或空值
- count(1):与
COUNT(*)
功能相同,计算所有行数,无论列值是否为null或空值
- 所有的统计函数都会忽略空值(null)
- avg(列名):计算指定列的平均值
- max(列名):返回指定列的最大值
- min(列名):返回指定列的最小值
- sum(列名):计算指定列的总和
2、SQL中的字符串操作函数
- LEFT(str, len):返回字符串str的前len个字符
- RIGHT(str, len):返回字符串str的后len个字符
- SUBSTRING(str, start, len):返回字符串str从start位置开始长度为len的子串
- TRIM(str):去除字符串str两端的空格
- REPLACE(str, old_substring, new_substring):将字符串str中的old_substring替换为new_substring
- INSTR(str1, str2):查找字符串str2在字符串str1中第一次出现的位置
- LENGTH(str):返回字符串str的长度
- CONCAT(str1, str2):连接两个字符串并返回结果
- CONCAT_WS(separator,str1,str2,...) 用分隔符将多个字符串连接起来
- GROUP_CONCAT([distinct]要连接的字段 [order by 排序字段 asc/desc][separator '分隔符']),分组聚合,将多个值连接成一个字符串
- SUBSTRING_INDEX(string, '切割标志', 位置数(负号:从后面开始)) 用于从给定的字符串中提取子字符串。
3、SQL中的日期函数
- date_add(date, interval 1/-1 day): 对指定日期加减操作
- last_day(date):所在月份最后一天
- dayofweek(date):返回整数从 `1` 到 `7` ,表示星期日到星期六
- datediff(time_end,time_start)------计算两个日期之间间隔的天数 日期差
- date_format(date,format):返回指定格式日期
- timestampdiff(unit, time_start, time_end)可计算指定单位的时间差
4、SQL中空字符串'',0,null,false的区别
- 空字符串'',表示一个空值或空文本,如果一个列中存储的是空字符串,那么这个列的值是存在的,但是它的长度为 0
- 0 一个整数类型的值,当它被指定为一个数字字段的值时,MySQL仍将其视为一个有效的值
- null表示表示未知值或不存在的值,如果一个列中存储的是 NULL,那么这个列的值是不存在的,无法比较大小或相等,也不能进行算术运算。NULL 不等于任何值,包括它本身
- FALSE: FALSE是一个布尔值,它表示为 0,使用布尔数据类型来存储。当将一个值插入到一个布尔类型的列中时,可以使用 1 或 0 来表示 TRUE 和 FALSE。
5、如何将 int 类型的字段转换为 string 字段
sql
select cast(int_column as char) from table_name
select convert(int_column, char) from table_name
6、SQL中的模糊匹配
like 和 rlike 都是用于模糊匹配的关键字
- like 是通配符,必须完全匹配。可以使用: _ 匹配任意一个字符,% 匹配0个或多个字符。
- rlike 是正则表达式,也可以用regexp
sql
# 假设使用的是 HQL,并且您有一个字符串"012daslSDAS589.",
# 您想要从中提取出小写英文字符,您可以使用以下语句:
select regexp_replace('012daslSDAS589.', '[^a-z]','') as res
7、SQL中on , where 和 having 的区别
ON、WHERE 和 HAVING 都是用于过滤数据的关键字。
- on用于表连接的子句,where用于过滤数据行的子句,都可以用来内连接查询
- 对于外连接(outer join)查询,ON 中的过滤条件在连接操作之前执行 ,WHERE 中的过滤条件(逻辑上)在连接操作之后执行
- having是用于过滤分组结果的子句,与 group by连用,可以使用聚合函数筛选,而where中不能使用聚合函数筛选。
- 在hive中,on不能用于不等式的链接,不能使用on a>b , 只能on a=b;但是mysql中可以
8、SQL中exists和in的区别
exists和in 都是用于子查询的关键字
- in:用于判断主查询某个列值是否等于子查询中返回结果集的任何一个值
- exists:判断查询结果集是否为空,与主表关联时,会进行一行行查询,过滤掉主查询中不存在的,留下存在的。EXISTS能判断多列比较,IN 只能判断一列比较。
- 从查询效率来看:
- 如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用 IN
- 如果外层的主查询记录较少,子查询中的表大又有索引时使用 EXISTS
9、SQL如何优化才能解决数据倾斜类问题
数据倾斜是指在 SQL 查询中,某些表或列的分布不平衡,导致查询效率低下,如何优化:
- 在表上使用合适的分布键(distribution key)和排序键(sort key),以确保数据均匀地分布在群集中
- 把大表拆成多个小表,使用 JOIN 或者 UNION ALL 进行关联处理,减少单个表的数据量
- 让查询尽可能走索引,避免全表扫描,可以使用 EXPLAIN 获得查询计划,并做出相应的调整
- 避免使用过多的where子查询,尤其是嵌套的子查询,会增加查询的时间复杂度
- 对于 GROUP BY 和 ORDER BY 操作,要考虑是否需要在分布键或排序键上进行操作,以最大程度利用分布式数据库系统的并行处理能力
- 如果数据倾斜问题无法通过优化查询来解决,则可能需要重新设计数据模型或使用更高级别的数据仓库工具来处理
10、如何优化SQL查询语句?
- 索引查询:确保 SQL 中使用了正确的索引,避免全表扫描。可以使用 EXPLAIN 或其他性能调试工具来检查查询计划和索引使用情况。
- 数据库范式化:通过将数据拆分成更小的表,并建立适当的关系,提高数据的规范化程度和查询效率
- 合理使用 JOIN:在使用 JOIN 时,要考虑到 JOIN 的顺序、连接类型以及连接字段等因素,以确保查询尽可能地使用索引并减少数据传输。
- 避免使用大型临时表:如果必须使用临时表,可以使用内存表或者临时表缓存技术,减少磁盘 IO 操作次数。
- 避免使用通配符:在 WHERE 子句中,尽量避免使用 % 来匹配文本,这样会导致全表扫描
- 避免使用 ORDER BY 子句中的函数:ORDER BY 子句中的函数会导致数据库进行计算,从而降低查询效率。因此,在可能的情况下,应该尽量避免在 ORDER BY 子句中使用函数。
- 减少子查询次数:每个子查询都需要执行一次查询操作,尽量避免嵌套次数太多的子查询
- 使用 UNION ALL 而不是 UNION:如果查询结果集的中间结果没有重复行,则可以使用 UNION ALL 替代 UNION,避免排序操作
- 缓存数据:对于一些只读的查询,可以使用缓存技术将结果集缓存在内存中,以避免重复查询
11、SQL去重的方法
- distinct关键字,可以去掉查询结果集中的重复行
- group by子句,将查询结果按照某个字段或多个字段进行分组,在分组后使用聚合函数(如 COUNT、SUM 等)可以去重并统计数据
- 子查询:在一个 SELECT 语句内嵌套另一个 SELECT 语句,通过 WHERE 子句和 EXISTS 或 NOT EXISTS 子句来进行查询。
- union去重,将多个 SELECT 语句的结果集合并成一个结果集,使用 UNION 可以去除重复行,而 UNION ALL 可以保留重复行
- 使用临时表,将查询结果插入到一个临时表中,然后再从临时表中进行查询操作,可以进行去重操作
- 使用窗口函数,在 SELECT 语句中使用窗口函数(如 RANK、ROW_NUMBER 等),可以对查询结果集进行排序和分组,同时去重。
12、窗口函数row_number()、rank()、dense_rank()的区别
- rank():相同值获得相同排名,但会跳过后续排名,------ 1 2 2 4
- dense_rank():相同值获得相同排名,但不会跳过后续排名。------ 1 2 2 3
- row_number():为每一行分配唯一的连续序号,即使有相同的排序值。------ 1 2 3 4
13、简述下SQL查询语句的执行顺序,要包含窗口函数
如果查询包含窗口函数,那么窗口函数会在 SELECT 子句执行之前被计算。具体来说,窗口函数的计算顺序如下:
- FROM、ON和WHERE:构造源表和筛选数据
- PARTITION BY 子句:将数据划分为不同的分区
- ORDER BY 子句:按照指定的列排序。
- 窗口框架:确定每一行的窗口范围
- 窗口函数:在每个窗口内计算函数值
- SELECT 子句:从临时表中选择需要的列
- ORDER BY 子句:按照指定的列排序
- LIMIT 或 OFFSET 子句:限制查询返回的结果集行数或跳过指定数量的行

14、partition by和group by 的区别?
- partition by用于窗口函数中,将结果集分成一组,为每组行计算单独的聚合值,然后将该聚合值添加到源表的每个行中。PARTITION BY 并不会减少结果集中的行数,而是基于源表的每一行计算一个聚合值
- GROUP BY 用于在查询结果集中根据给定的列对数据进行分组,常与聚合函数一起使用,会较少结果集的行数
15、什么是笛卡尔积?笛卡尔积问题一般出现在什么场景?
笛卡尔积(Cartesian Product)是指对两个或多个表进行无条件连接,返回的结果是这些表中所有可能的组合。所有连接方式都会先生成临时笛卡尔积表
笛卡尔积问题通常出现在以下场景:、
- 没有明确指定连接条件的 JOIN 查询。当查询中忘记指定JOIN语句或忘记提供连接条件时,MySQL会默认执行笛卡尔积操作。这可能导致结果集迅速膨胀,产生大量不必要的数据。
- 子查询中使用了不相关的表或视图,导致数据重复
- 在数据仓库或 OLAP 系统中,使用多个维度表进行联接查询时,容易产生笛卡尔积。
为避免笛卡尔积问题,应注意以下几点:
- 明确指定连接条件
- 检查连接条件的准确性:确保连接条件中使用的列与表之间的关联是准确的
- 使用合适的连接类型:根据业务需求选择适当的连接类型(如INNER JOIN、LEFT JOIN、RIGHT JOIN等),以避免不必要的笛卡尔积产生。
16、SQL中有哪些表连接方式?
- inner join/join:只返回两个表中满足连接条件的行,使用on子句指定连接条件
- left join:将左表的所有行与右表中满足连接条件的行进行连接,如果右表中没有与左表匹配的行,则右表的值为 NULL
- right join:将右表的所有行与左表中满足连接条件的行进行连接,如果左表中没有与右表匹配的行,则左表的值为 NULL
- full join:全连接是将左表和右表中的所有行都进行连接,无论是否满足连接条件。如果某一侧没有匹配的行,则对应的值为 NULL
- self join:自连接是将同一张表中的行进行连接。通常用于需要比较表中不同记录之间的关系的情况
- cross join:交叉连接是对两个表进行笛卡尔积操作的结果,它将左表中的每一行都与右表中的每一行进行连接
16、SQL中on和using 的区别
- ON 可以用于连接多个表或连接单个表时需要更复杂的条件,而 USING 只能用于连接两个表,并且连接的列名必须相同
- ON 需要指定列名和比较条件,而 USING 只需要指定列名即可
- ON 比 USING 更灵活,可以处理更多种类的连接条件
- 最终生成的结果集中,使用on,两个表的列名都会保留,若列名相同会增加表明。使用using只保留一个列名
17、主键,外键和索引的区别
- 主键是用于唯一标识表中每条记录的标识符;外键是用于在表之间建立关系的键;索引是用于加速查询操作的数据结构。
- 主键和外键都是用于保持数据完整性和一致性的,而索引则是提高查询性能的工具,但同时也会降低插入、更新、删除等操作的速度。
- 主键和外键通常需要定义在数据库设计阶段,而索引可以在运行时动态创建或删除
- 主键和外键只能唯一地标识一条记录或连接两个表,而索引可以建立在一个或多个列上以提高查询效率。