基础SQL的练习及解析

基础SQL的练习及解析

简单处理查询结果

去重:DISTINCT或GROUP BY

  • 示例:

    一:SELECT university from user_profile GROUP BY university;
    二:SELECT DISTINCT university from user_profile;
    
  • 解析:

    distinct和group by区别
    
    distinct:
    
    distinct 只能放在查询字段的最前面,不能放在查询字段的中间或者后面。
    
    distinct 对后面所有的字段均起作用,即 去重是查询的所有字段完全重复的数据,而不是只对 distinct 后面连接的单个字段重复的数据。
    
    要查询多个字段,但只针对一个字段去重,使用distinct去重的话是无法实现的。
    
    group by
    
    一般与聚类函数使用(如count()/sum()等),也可单独使用。
    
    group by 也对后面所有的字段均起作用,即 去重是查询的所有字段完全重复的数据,而不是只对 group by后面连接的单个字段重复的数据
    
    查询的字段与group by 后面分组的字段没有限制。(在oracle中使用group by时,查询的字段必须是group by 分组的字段和聚类函数。如select name,sex from tb_students group by name这个sql)
    

限制返回行数:limit

  • 示例:

    SELECT DEVICE_ID FROM USER_PROFILE LIMIT 2;
    
  • 解析:

    LIMI用法:
    --LIMIT n:从第0+1(m=0)条开始,取n条数据,是LIMIT 0,n的缩写
    SELECT device_id
    FROM user_profile
    LIMIT 2 
    
    --LIMIT m,n:从第m+1条开始,取n条数据
    SELECT device_id
    FROM user_profile
    LIMIT 0,2
    
    --LIMIT n OFFSET m:从第m+1条开始,取n条数据
    SELECT device_id
    FROM user_profile
    LIMIT 2 OFFSET 0
    

列重命名:AS

  • 示例:

    select 
        device_id 'user_infos_example'
    from 
        user_profile
    limit 2;
    
  • 解析:

    语法:
    1 列名 | 表达式 [ AS ] 新列名
    或:
    1 新列名=列名 | 表达式
    
    例:
    SELECT 姓名, year (getdate())-year(出生日期) AS 年龄 FROM 学生表
    

条件查询:where

基础操作:等于、不等于、大于、小于、逻辑运算、范围查询、模糊查询、空值匹配

  • 示例:

    select device_id,university from user_profile where university = "北京大学";
    
  • 解析:

    以下是一些常见的WHERE子句用法示例,涵盖了基本比较、逻辑运算、范围查询、模式匹配等方面:
    
    基本比较:
    等于:
    	WHERE column = value
    	SELECT * FROM Products WHERE Price = 99.99;
    
    不等于:
    	WHERE column != value 或 WHERE column <> value
    	SELECT * FROM Employees WHERE Department != 'Sales';
    
    大于:
    	WHERE column > value
        SELECT * FROM Orders WHERE OrderDate > '2023-01-01';
    
    小于:
    	WHERE column < value
    	SELECT * FROM Students WHERE Grade < 70;
    
    大于等于/小于等于:
    	WHERE column >= value / WHERE column <= value
    
    逻辑运算:
    	AND:同时满足两个条件
    	SELECT * FROM Books WHERE Author = 'J.K. Rowling' AND YearPublished > 2000; 
    	
    	OR:满足任一条件
    	SELECT * FROM Customers WHERE Country = 'USA' OR Country = 'Canada';
    	
    	NOT:否定条件
    	SELECT * FROM Products WHERE NOT Discontinued;
    	
    范围查询:
    BETWEEN: 在两个值之间(包括边界)
    
         SELECT * FROM Employees WHERE HireDate BETWEEN '2018-01-01' AND '2025-12-31';
         
    
    模式匹配:
    LIKE: 用于模糊查询,%是通配符,代表零个、一个或多个字符
         SELECT * FROM Products WHERE ProductName LIKE '%Chocolate%';
         
    
    IN: 列出一系列可能的值
         SELECT * FROM Departments WHERE DepartmentName IN ('HR', 'IT', 'Finance');
         
    
    空值处理:
    IS NULL: 查找空值
    SELECT * FROM Customers WHERE Email IS NULL;
    
    IS NOT NULL: 查找非空值
    SELECT * FROM Orders WHERE ShippingAddress IS NOT NULL;  
    
    这些只是冰山一角,WHERE子句还能与函数、子查询等配合使用,以应对更复杂的查询需求。
    

基础排序:单列排序、多列排序、多列混合排序

查询后排序是非常常见的需求,你可以使用SQL的ORDER BY子句来实现。ORDER BY允许你根据一列或多列的值对查询结果进行排序,你可以选择升序(ASC,默认)或降序(DESC)排列。
基本语法:
SELECT column1, column2, ...
FROM table_name
ORDER BY column_to_sort ASC|DESC;

如果你需要按多个列排序,只需在ORDER BY后列出所有列名,并可以为每个列指定排序方向。
如果没有指定排序方向,默认为升序(ASC)。

示例:
单列升序排序: 假设你有一个Employees表,想要按姓名字母顺序显示所有员工:
	SELECT * FROM Employees ORDER BY Name ASC;  

单列降序排序: 按工资从高到低显示员工:
	SELECT * FROM Employees ORDER BY Salary DESC;

多列排序: 先按部门排序,然后在同一部门内按入职日期排序:
	SELECT * FROM Employees ORDER BY Department, HireDate ASC;

多列混合排序: 首先按部门降序,然后在每个部门内部按工资升序:

   SELECT * FROM Employees ORDER BY Department DESC, Salary ASC;
   
排序操作可能会消耗较多资源,特别是对于大数据集。因此,在考虑性能时,尽量避免对大型表进行全表排序,除非绝对必要。

计算函数:最大值与平均值

最大值:MAX()
SELECT MAX(column_name) AS max_value
FROM table_name;

平均值:AVG()
SELECT AVG(column_name) AS average_value
FROM table_name;

分组查询:分组计算、分组过滤、分组排序

分组计算 (GROUP BY + 聚合函数)

分组计算是指将数据按照一个或多个列的值分组,并对每个组应用聚合函数以计算各组的统计值,如总和、平均值、最大值、最小值或计数等。
示例:计算每个部门的总工资
SELECT Department, SUM(Salary) AS TotalSalary
FROM Employees
GROUP BY Department;

分组过滤 (HAVING)

HAVING子句用于在分组后对结果进行过滤,它允许你设置条件来排除某些分组。
注意,HAVING不能被WHERE替代,因为WHERE是在分组操作之前过滤行,而HAVING是在分组之后。

示例:只显示总工资超过50000的部门
SELECT Department, SUM(Salary) AS TotalSalary
FROM Employees
GROUP BY Department
HAVING SUM(Salary) > 50000;

分组排序 (ORDER BY)

虽然ORDER BY本身不是分组操作的一部分,但它经常与GROUP BY一起使用,以便对分组后的结果进行排序。你可以根据分组的列或聚合函数的结果来排序。
示例:按总工资降序排列部门
SELECT Department, SUM(Salary) AS TotalSalary
FROM Employees
GROUP BY Department
HAVING SUM(Salary) > 50000
ORDER BY TotalSalary DESC;

多表查询:

子查询

子查询(Subquery)

子查询是指嵌套在另一个查询中的查询,它作为一个表达式被外部查询使用。
子查询可以用来提供一个值、一列值或一组行给外部查询作为条件或数据源。

示例:查找比平均工资高的员工
SELECT EmployeeName, Salary
FROM Employees
WHERE Salary > (
    SELECT AVG(Salary)
    FROM Employees
);

在这个例子中,子查询计算了所有员工的平均工资,外部查询则用这个平均值作为条件,找出工资高于平均值的员工。

链表查询

连接查询(JOIN)

连接查询用于结合来自两个或更多表中的行,基于这些表之间的相关列。最常见的连接类型包括:

内连接(INNER JOIN):返回两个表中匹配的行。
左连接(LEFT JOIN):返回左表的所有行,即使右表中没有匹配。
右连接(RIGHT JOIN):返回右表的所有行,即使左表中没有匹配。
全外连接(FULL OUTER JOIN):返回左表和右表中所有匹配和不匹配的行。

示例:内连接员工表和部门表
SELECT Employees.EmployeeName, Departments.DepartmentName
FROM Employees
INNER JOIN Departments ON Employees.DepartmentID = Departments.DepartmentID;

此查询将员工表和部门表根据部门ID连接起来,展示每位员工所属的部门名称。

组合查询

组合查询(Set Operations)

组合查询使用UNION、UNION ALL、INTERSECT和EXCEPT操作符来合并或比较来自多个SELECT语句的结果集。

UNION:合并两个结果集,自动去除重复行。
UNION ALL:合并两个结果集,保留所有行,包括重复行。
INTERSECT:返回两个结果集的交集,即同时存在于两个结果集中的行。
EXCEPT:返回第一个结果集中有但第二个结果集中没有的行。

示例:使用UNION合并两个查询结果
(SELECT EmployeeName, Salary FROM Employees WHERE Department='Sales')
UNION
(SELECT EmployeeName, Bonus FROM Bonuses WHERE Year=2023);

这个例子展示了如何合并两组数据:一个是销售部门员工的薪资,另一个是2023年发放的奖金记录,结果集中会去除重复行。

常用函数

条件函数

CASE表达式允许你根据一个或多个条件来返回不同的值,它在处理复杂的条件逻辑时非常有用。

CASE表达式基本语法如下:

CASE
    WHEN condition1 THEN result1
    WHEN condition2 THEN result2
    ...
    [ELSE else_result]
END;

WHEN conditionN THEN resultN:如果conditionN为真,则返回resultN。
[ELSE else_result]:可选部分,如果没有匹配的WHEN条件,则返回这里的默认值。

示例

假设有一个员工表,你要根据员工的等级(Level)计算奖金(Bonus),规则如下:
等级1:奖金为工资的10%
等级2:奖金为工资的15%
其他等级:奖金为工资的20%
可以使用CASE表达式来实现这个逻辑:
SELECT 
    EmployeeID, 
    Salary,
    CASE 
        WHEN Level = 1 THEN Salary * 0.1
        WHEN Level = 2 THEN Salary * 0.15
        ELSE Salary * 0.2
    END AS Bonus
FROM Employees;

在这个查询中,CASE表达式根据每个员工的等级来决定奖金的计算比例,然后将计算结果作为Bonus列返回。


其他类似功能的函数

在某些数据库系统中,还可能有其他函数提供类似条件处理的功能,比如Oracle的DECODE函数,它也允许根据条件返回不同值,但语法与CASE有所不同。然而,CASE表达式由于其标准性和灵活性,在多数情况下是首选的解决方案。

日期函数

MySQL中的日期函数

CURRENT_DATE 或 CURRENT_DATE() - 返回当前日期。
CURDATE() - 同CURRENT_DATE,返回当前日期。
CURRENT_TIME 或 CURRENT_TIME() - 返回当前时间。
CURTIME() - 同CURRENT_TIME,返回当前时间。
NOW() - 返回当前的日期和时间。
DATE(date) - 提取日期部分,从日期/时间表达式。
YEAR(date) - 返回日期的年份部分。
MONTH(date) - 返回日期的月份部分。
DAY(date) - 返回日期的日部分。
HOUR(time) - 返回时间的小时部分。
MINUTE(time) - 返回时间的分钟部分。
SECOND(time) - 返回时间的秒部分。
ADDDATE(date, INTERVAL expr unit) - 在日期上添加指定的时间间隔。
SUBDATE(date, INTERVAL expr unit) - 从日期中减去指定的时间间隔。
DATE_FORMAT(date, format) - 格式化日期时间值,如'%Y-%m-%d'。
DATEDIFF(date1, date2) - 计算两个日期之间的天数差。


SQL Server中的日期函数

GETDATE() - 返回当前的日期和时间。
DATEPART(part, date) - 返回日期时间的指定部分,如年、月、日等。
DATEADD(interval, number, date) - 在日期上增加指定的时间间隔。
DATEDIFF(interval, date1, date2) - 计算两个日期之间的时间间隔,单位由interval指定。
CONVERT(data_type, date_expression, style_number) - 转换日期/时间数据类型或格式化日期输出。
示例:

MySQL 示例

获取当前日期和时间
   SELECT NOW();
获取今天的日期
   SELECT CURDATE();
获取时间的部分,例如小时
   SELECT HOUR(NOW());
计算两个日期之间的天数差
   SELECT DATEDIFF('2024-08-01', '2024-07-31');
格式化日期输出
   SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s');
向日期添加一个月
   SELECT ADDDATE(NOW(), INTERVAL 1 MONTH);

SQL Server 示例

获取当前日期和时间
   SELECT GETDATE();
获取年份
   SELECT DATEPART(YEAR, GETDATE());
获取月份
   SELECT DATEPART(MONTH, GETDATE());
获取日期的部分,例如天
   SELECT DATEPART(DAY, GETDATE());
计算两个日期之间的月数差
   SELECT DATEDIFF(MONTH, '2024-06-01', '2024-07-31');
格式化日期输出
   SELECT CONVERT(VARCHAR, GETDATE(), 120); -- 'YYYY-MM-DD'
向日期添加一周
   SELECT DATEADD(WEEK, 1, GETDATE());

文本函数

UPPER(text): 将文本字符串转化为大写。
   SELECT UPPER('Hello World'); 
   -- 结果: HELLO WORLD

LOWER(text): 将文本字符串转化为小写。
   SELECT LOWER('Hello World'); 
   -- 结果: hello world

LENGTH(text) 或 LEN(text): 返回文本字符串的长度(字符数)。
   SELECT LENGTH('Hello'); 
   -- 结果: 5

SUBSTRING(text, start, length) 
或 SUBSTR(text, start, length): 从文本字符串中提取子串,start是开始位置,length是要提取的字符数。
   SELECT SUBSTRING('Hello World', 7, 5); 
   -- 结果: World
   
TRIM([characters FROM] text): 移除文本字符串首尾的空格或指定字符。
   SELECT TRIM('   Hello   '); 
   -- 结果: Hello
   
LTRIM(text): 移除文本字符串开头的空格。
   SELECT LTRIM('   Hello'); 
   -- 结果: Hello
   

RTRIM(text): 移除文本字符串末尾的空格。
   SELECT RTRIM('Hello   '); 
   -- 结果: Hello
   

REPLACE(text, search, replacement): 替换文本字符串中的某个子串。
   SELECT REPLACE('Hello World', 'World', 'Universe'); 
   -- 结果: Hello Universe

CONCAT(text1, text2, ...) 或 ||(在某些数据库中): 连接两个或多个文本字符串。
   SELECT CONCAT('Hello', ' ', 'World');
   -- 结果: Hello World
   

INSTR(text, substring) 
或 POSITION(substring IN text) 
或 LOCATE(substring, text): 返回子串在文本字符串中的起始位置。如果未找到,返回值可能为0或NULL,具体取决于数据库系统。
    SELECT INSTR('Hello World', 'World'); 
    -- 结果: 7
    
Soundex(text): 返回文本字符串的Soundex值,这是一种编码方式,用于表示字符串的英语发音,常用于模糊搜索或姓名匹配。
    SELECT Soundex('Smith'); 
    -- 结果可能为: S500

窗口函数

窗口函数详解链接:https://zhuanlan.zhihu.com/p/92654574

窗口函数在SQL中是一种强大的分析工具,它允许你在一组相关的行(称为“窗口”)上执行计算,而不是在整个查询结果集上。窗口函数通过引入OVER子句来定义这个窗口的范围,并且可以在每个窗口内进行排序、聚合等操作,而不会影响到整个查询的行结构。以下是一些关键点和示例来帮助理解窗口函数:


窗口函数的关键概念:

窗口定义:通过OVER()子句定义,可以包括分区(PARTITION BY)、排序(ORDER BY)和帧(ROWS BETWEEN)等子句来精确控制窗口的范围。

分区(PARTITION BY):将数据分成多个独立的组(或分区),在每个分区内独立执行窗口函数。

排序(ORDER BY):在窗口内对行进行排序,这对于许多需要顺序计算的函数(如排名函数)至关重要。

帧(Frame):定义窗口的一个子集,可以是固定的行数(如前N行、后N行或两者之间的行),或基于当前行的偏移量。


常见的窗口函数示例:

ROW_NUMBER():为窗口内的每一行分配一个唯一的、连续的整数。
   SELECT EmployeeID, Salary, ROW_NUMBER() OVER (ORDER BY Salary DESC) AS Rank
   FROM Employees;
   

RANK() 和 DENSE_RANK():为窗口内的行提供排名,其中RANK()会跳过相同排名后的序号,而DENSE_RANK()则不会跳过。
RANK:1 2 2 4
DENSE_RANK():1 2 2 3
	SELECT EmployeeID, Salary, RANK() OVER (ORDER BY Salary DESC) AS Rank
  	FROM Employees;


LAG() 和 LEAD():获取当前行之前或之后的行的值。
   SELECT EmployeeID, Salary, LAG(Salary) OVER (ORDER BY Salary) AS PrevSalary
   FROM Employees;
   

SUM()、AVG()、COUNT()等聚合函数:在窗口内执行聚合操作。
   SELECT EmployeeID, Salary, AVG(Salary) OVER (PARTITION BY DepartmentID) AS AvgDeptSalary
   FROM Employees;
   

NTILE(n):将行分入指定数量的桶(或组)中。
   SELECT EmployeeID, Salary, NTILE(4) OVER (ORDER BY Salary) AS Quartile
   FROM Employees;
   

窗口函数的应用非常广泛,特别是在数据分析和报表制作中,它们可以帮助进行复杂的分组分析、动态计算以及实现各种排名和百分位统计等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值