要开始与数据打交道,了解像SQL这样的工具是非常重要的。SQL是一种编程语言,用于存储、处理和管理关系数据库中的数据,不过,它的应用现在已经超出了关系数据库的范围,比如在Big Data(大数据)处理方面。
自20世纪70年代以来引入的SQL在数据工程、数据分析和数据科学等领域中仍是核心工具。该语言可以在多种平台上运行,例如SQL Server、Oracle、PostgreSQL、Snowflake、Google BigQuery以及基于Spark的平台,例如Databricks。
即使你只打算用Python、R或其他编程语言来做数据工程师或数据科学家,不学SQL也几乎是不可能的。
公用表表达式 (CTE)通用表表达式(CTE)被引入SQL以简化SQL查询过程。CTE是一个临时的结果集,可以在SELECT
、INSERT
、UPDATE
或DELETE
语句中引用它。它允许我们将复杂的查询拆分为更小、更易读的部分。
递归CTE是CTE一个非常实用的功能,它可以帮助您解决诸如层级数据查询等问题,例如组织中的员工层级结构,或生成像日历这样的序列数据。
下面是一个创建表并插入记录的SQL代码的例子。
创建表 Employees 如下,
(
EmployeeID int,
名字 string,
姓氏 string,
经理ID int
)
插入 INTO Employees 值 (1, '哈珀', '韦斯特布鲁克', 空);
插入 INTO Employees 值 (2, '莱姆', '卡林顿', 1);
插入 INTO Employees 值 (3, '埃弗琳', '拉德克利夫', 1);
插入 INTO Employees 值 (4, '梅森', '艾尔布赖特', 2);
插入 INTO Employees 值 (5, '伊莎拉', '惠特曼', 2);
插入 INTO Employees 值 (6, '诺亚', '斯廷格尔', 3);
插入 INTO Employees 值 (7, '鲁比', '伦诺克斯', 3);
插入 INTO Employees 值 (8, '卡莱布', '温斯洛', 5);
插入 INTO Employees 值 (9, '艾弗莉', '辛克莱尔', 6);
插入 INTO Employees 值 (10, '奥利弗', '贝克特', 6).
以下代码将生成一个包含员工及其对应经理信息的结果。通过使用 自连接,我们将根据 “MgrID”
将每个员工与其对应的经理匹配起来。
WITH RECURSIVE
cteReports (EmpID, FirstName, LastName, MgrID, EmpLevel)
AS
(
SELECT EmployeeID, FirstName, LastName, ManagerID, 1
FROM Employees
WHERE ManagerID IS NULL
UNION ALL
SELECT e.EmployeeID, e.FirstName, e.LastName, e.ManagerID,
r.EmpLevel + 1
FROM Employees e
INNER JOIN cteReports r
ON e.ManagerID = r.EmpID
)
SELECT
FirstName || ' ' || LastName AS FullName,
EmpLevel,
(SELECT FirstName || ' ' || LastName FROM Employees
WHERE EmployeeID = cteReports.MgrID) AS Manager
FROM cteReports
ORDER BY EmpLevel, MgrID
结果是这样的:
比如,在数据仓库中进行基于日期的分析时,创建日期维度表很有用。日期维度表以一种结构化的方式来处理日期范围、节假日、财政年度及其他时间相关的属性。
以下是一个示例,演示如何使用递归CTE(通用表表达式)来生成日期维度表。递归CTE是一种可以在SQL中用来解决需要递归查询的数据问题的技术。日期维度表是一种包含多个日期维度信息的表格。
WITH RECURSIVE dates (Date) AS (
SELECT cast('2024-01-01' AS date) AS Date, extract('year' FROM cast('2024-01-01' AS date)) AS year, extract('month' FROM cast('2024-01-01' AS date)) AS month
UNION ALL
SELECT Date + INTERVAL '1' DAY, extract('year' FROM Date + INTERVAL '1' DAY) AS year, extract('month' FROM Date + INTERVAL '1' DAY) AS month
FROM dates
WHERE Date <= '2025-12-31' -- 请在这里填入结束日期
)
SELECT *
FROM dates;
在Databricks SQL里,不支持递归公用表表达式。但是,你可以使用**EXPLODE**
函数达到相同的效果。
当我们处理原始数据时,一个常见的场景是需要去除重复项或仅获取最新的版本。在 SQL 中,使用 ROW_NUMBER()
窗口函数是一种高效处理这种情况的方法。该函数允许你根据指定的排序方式为数据分区内的每一行分配一个唯一的行号。
以下是一个使用 ROW_NUMBER()
来选择记录最新版本的示例。
查询会把记录编号,最新的记录会被编号为1。这样我们就能从表中筛选出最新的记录。
-- 以下是一些示例数据
with dane (id, name, age, date) as
(
select 1, 'John Smit', 19, '2020-01-01'
UNION ALL
select 2, 'Eva Nowak', 21, '2021-01-01'
UNION ALL
select 3, 'Danny Clark', 24, '2021-01-01'
UNION ALL
select 4, 'Alicia Kaiser', 25, '2021-01-01'
UNION ALL
select 5, 'John Smit', 19, '2021-01-01'
UNION ALL
select 6, 'Eva Nowak', 21, '2022-01-01'
)
select *
from (
select
row_number() over (partition by name order by date) rn,
*
from
dane
)
where
rn = 1
;
使用子查询删除重复行
在SQL里,有许多方法可以达到相同的结果。我们可以使用一个(子查询)来找出每个组里的最新记录,然后用一个INNER JOIN来排除重复记录。
WITH dane (id, name, 年龄, 日期) AS
(
SELECT 1, 'John Smit', 19, '2020-01-01'
UNION ALL -- 合并重复记录
SELECT 2, 'Eva Nowak', 21, '2021-01-01'
UNION ALL -- 合并重复记录
SELECT 3, 'Danny Clark', 24, '2021-01-01'
UNION ALL -- 合并重复记录
SELECT 4, 'Alicia Kaiser', 25, '2021-01-01'
UNION ALL -- 合并重复记录
SELECT 5, 'John Smit', 19, '2021-01-01'
UNION ALL -- 合并重复记录
SELECT 6, 'Eva Nowak', 21, '2022-01-01'
)
SELECT
a.*
FROM
dane a
INNER JOIN ( -- 内连接,选择每个名字的最新日期
SELECT
name, MAX(日期) 最后日期 FROM dane GROUP BY name -- 按名称分组
) b ON a.name = b.name AND a.日期 = b.最后日期 -- 连接条件
;
该子查询**b**
**** 找出每个名称的最大日期。然后我们根据子查询的结果,只保留最近日期的记录。
例:
查找新条目或不存在的条目当从源表加载数据时,一个常见的任务是加载仅新的记录,即之前不在目标表中的记录。一个有效的方法是使用 SQL 中的 **EXISTS**
命令,这个命令可以检查源表中的记录是否已在目标表中存在。如果不存在,就可以插入或处理该记录。
用于练习的测试数据 (yóu yú liànxiàn de cèshī shùjù)
假设 raw_Employees
是原始的表格,Employees
是我们要转换的目标表格。
创建表 Employees
(
EmployeeID int,
FirstName string,
LastName string,
ManagerID int
);
INSERT INTO Employees VALUES (1, 'Harper', 'Westbrook', NULL);
INSERT INTO Employees VALUES (2, 'Liam', 'Carrington', 1);
INSERT INTO Employees VALUES (3, 'Evelyn', 'Radcliffe', 1);
INSERT INTO Employees VALUES (4, 'Mason', 'Albright', 2);
INSERT INTO Employees VALUES (5, 'Isla', 'Whitman', 2);
INSERT INTO Employees VALUES (6, 'Noah', 'Sterling', 3);
INSERT INTO Employees VALUES (7, 'Ruby', 'Lennox', 3);
INSERT INTO Employees VALUES (8, 'Caleb', 'Winslow', 5);
INSERT INTO Employees VALUES (9, 'Avery', 'Sinclair', 6);
INSERT INTO Employees VALUES (10, 'Oliver', 'Beckett', 6);
创建表 raw_Employees
(
EmployeeID int,
FirstName string,
LastName string,
ManagerID int
);
INSERT INTO raw_Employees VALUES (1, 'Harper', 'Westbrook', NULL);
INSERT INTO raw_Employees VALUES (2, 'Liam', 'Carrington', 1);
INSERT INTO raw_Employees VALUES (3, 'Evelyn', 'Radcliffe', 1);
INSERT INTO raw_Employees VALUES (4, 'Mason', 'Albright', 2);
INSERT INTO raw_Employees VALUES (5, 'Isla', 'Whitman', 2);
INSERT INTO raw_Employees VALUES (6, 'Noah', 'Sterling', 3);
INSERT INTO raw_Employees VALUES (7, 'Ruby', 'Lennox', 3);
INSERT INTO raw_Employees VALUES (8, 'Caleb', 'Winslow', 5);
INSERT INTO raw_Employees VALUES (9, 'Avery', 'Sinclair', 6);
INSERT INTO raw_Employees VALUES (10, 'Oliver', 'Beckett', 6);
INSERT INTO raw_Employees VALUES (11, 'Avery', 'Sinclair', 6);
INSERT INTO raw_Employees VALUES (12, 'Oliver', 'Beckett', 6);
我们可以用 EXISTS
命令来过滤掉源数据中已经在目标中存在的情况。
SELECT *
FROM
raw_Employees a
WHERE
NOT EXISTS (
SELECT 1
FROM
Employees b
WHERE
a.EmployeeID = b.EmployeeID
)
/ 此查询从 raw_Employees 表中选择所有行,其中 EmployeeID 不在 Employees 表中。/
注意:SQL 术语如 "SELECT", "FROM", "WHERE" 保持不变,表名和列名 "raw_Employees", "Employees", "EmployeeID" 也不翻译,因为它们是特定的标识符。
这可能在报告目的时或仅当向事实表或维度表添加新记录时很有帮助。
另一种方式是使用 LEFT JOIN
和 WHERE
条件。这个查询会筛选出不在目标表中的记录。
SELECT a.*
FROM
raw_Employees a
left join
Employees b on a.EmployeeID = b.EmployeeID
WHERE
b.EmployeeID is null;
/ 从raw_Employees表中选择所有在Employees表中没有对应记录的员工信息 /
/ 从raw_Employees表中选择所有在Employees表中没有对应记录的员工信息,这里的查询目的是找出那些在Employees表中没有匹配记录的员工数据。 /
当处理数据时,一个常见的任务是检查特定记录是否存在于另一个表中。你可能需要创建一个只显示活跃客户的报告。为了找出这些客户,你可以看看特定的 CustomerID
是否出现在另一个表中。
在这种情况下,可以使用 EXISTS
命令(即EXISTS
命令)来满足这个需求。
-- 示例数据如下
CREATE TABLE Customers
(
CustomerID int,
FirstName string,
LastName string
);
INSERT INTO Customers VALUES (1, 'Harper', 'Westbrook');
INSERT INTO Customers VALUES (2, 'Liam', 'Carrington');
INSERT INTO Customers VALUES (3, 'Evelyn', 'Radcliffe');
INSERT INTO Customers VALUES (4, 'Mason', 'Albright');
INSERT INTO Customers VALUES (5, 'Isla', 'Whitman');
INSERT INTO Customers VALUES (6, 'Noah', 'Sterling');
INSERT INTO Customers VALUES (7, 'Ruby', 'Lennox');
INSERT INTO Customers VALUES (8, 'Caleb', 'Winslow');
INSERT INTO Customers VALUES (9, 'Avery', 'Sinclair');
INSERT INTO Customers VALUES (10, 'Oliver', 'Beckett');
INSERT INTO Customers VALUES (11, 'Avery', 'Sinclair');
INSERT INTO Customers VALUES (12, 'Oliver', 'Beckett');
CREATE TABLE orders
(
OrderID int,
CustomerID int,
Quantity int,
Price decimal(10,2),
ProductID int
);
INSERT INTO orders VALUES (1,1, 10, 5.2, 1);
INSERT INTO orders VALUES (2,2, 5, 5.2, 1);
INSERT INTO orders VALUES (3,3, 2, 5.2, 1);
INSERT INTO orders VALUES (4,4, 4, 5.2, 1);
INSERT INTO orders VALUES (5,5, 11, 5.2, 1);
INSERT INTO orders VALUES (6,6, 1, 5.2, 1);
INSERT INTO orders VALUES (7,7, 1, 5.2, 1);
-- 查询活跃的客户信息
select *
from
Customers a
WHERE
EXISTS (
SELECT 1 from orders b
WHERE
a.CustomerID = b.CustomerID
)
结果应该是这样:
活跃用户
如果我们在这条 EXISTS
命令前加上 NOT
,就能获取那些未下单的未活跃客户的信息。
SELECT *
FROM
客户 a
WHERE
NOT EXISTS (
SELECT 1 FROM 订单 b
WHERE
a.CustomerID = b.CustomerID
)
/* 查询没有订单的客户 */
不活跃的客户
使用 SQL:填补数据空白您可能会遇到的一个常见问题是数据中的缺失条目。例如,在导入有关货币的数据时,因为数据只在工作日发布,因此可能会出现空缺。这些空缺需要被填补,以确保我们的计算和报告正常进行。如下屏幕所示,在黄色标记的记录之间存在数据空白。
空档
我们该怎么解决这个问题呢?
为了处理这个问题,我们需要使用一个包含所有所需日期的日历表。我使用了一个递归的CTE来生成日历表。
WITH RECURSIVE 日期表 (日期) AS (
SELECT cast('2006-01-01' as date) as 日期
UNION ALL
SELECT date_add(日期, INTERVAL 1 day)
FROM 日期表
WHERE 日期 <= '2006-01-31' -- 将结束日期放在这里
)
, 货币表 (日期, 价格, 货币) AS (
SELECT cast('2006-01-02' as date) ,3.2582, 'USD'
UNION SELECT cast('2006-01-03' as date) ,3.2488 , 'USD'
UNION SELECT cast('2006-01-04' as date) ,3.1858 , 'USD'
UNION SELECT cast('2006-01-05' as date) ,3.1416 , 'USD'
UNION SELECT cast('2006-01-06' as date) ,3.1507 , 'USD'
-- 数据缺失
UNION SELECT cast('2006-01-09' as date) ,3.1228 , 'USD'
UNION SELECT cast('2006-01-10' as date) ,3.128 , 'USD'
UNION SELECT cast('2006-01-11' as date) ,3.1353 , 'USD'
UNION SELECT cast('2006-01-12' as date) ,3.1229 , 'USD'
UNION SELECT cast('2006-01-13' as date) ,3.1542 , 'USD'
-- 数据缺失
UNION SELECT cast('2006-01-16' as date) ,3.1321 , 'USD'
UNION SELECT cast('2006-01-17' as date) ,3.1521 , 'USD'
UNION SELECT cast('2006-01-18' as date) ,3.1887 , 'USD'
UNION SELECT cast('2006-01-19' as date) ,3.1772 , 'USD'
UNION SELECT cast('2006-01-20' as date) ,3.1868 , 'USD'
-- 数据缺失
UNION SELECT cast('2006-01-23' as date) ,3.1397 , 'USD'
UNION SELECT cast('2006-01-24' as date) ,3.1333 , 'USD'
UNION SELECT cast('2006-01-25' as date) ,3.095 , 'USD'
UNION SELECT cast('2006-01-26' as date) ,3.1253 , 'USD'
UNION SELECT cast('2006-01-27' as date) ,3.1379 , 'USD'
-- 数据缺失
UNION SELECT cast('2006-01-30' as date) ,3.1559 , 'USD'
UNION SELECT cast('2006-01-31' as date) ,3.163 , 'USD'
)
SELECT
日期,
价格,
货币
FROM
(
SELECT
ROW_NUMBER() over (PARTITION BY 货币, a.日期 ORDER BY b.日期 DESC) lp,
a.日期,
b.日期 org_date,
b.价格,
货币
FROM
日期表 a LEFT JOIN
货币表 b ON b.日期 BETWEEN a.日期 - INTERVAL 3 DAY AND a.日期
)
WHERE
lp = 1
ORDER BY 日期;
通过这个查询,我们可以用前一天的数据填补空缺。下面就是查询的结果。
填上的空隙
找到薪水最高的员工找到像最高薪资的员工或最高消费的客户这样的实体时,可以使用LIMIT
和ORDER BY
命令。但是,如果有多个实体的值相同,我们可能在结果中看不到所有这些实体。为了解决这个问题,我们可以使用子查询,如下例所示。
WITH Employees (EmployeeID, Name, Salary) AS (
SELECT 1, 'John', 5000
UNION ALL SELECT 2, 'Jane', 7000
UNION ALL SELECT 3, 'Bob', 4500
UNION ALL SELECT 4, 'Alice', 9000
UNION ALL SELECT 5, 'Mike', 9000
UNION ALL SELECT 6, 'Sara', 8000
UNION ALL SELECT 7, 'Tom', 6000
UNION ALL SELECT 8, 'Lucy', 5500
UNION ALL SELECT 9, 'Mary', 5820
UNION ALL SELECT 10, 'Tom', 7890
)
SELECT
a.*
FROM Employees a
INNER JOIN (
SELECT DISTINCT Salary FROM Employees ORDER BY Salary DESC LIMIT 3
) AS b
ON a.Salary = b.Salary;
正如你所见,我们试图找出薪水最高的三位员工,然而由于有两个人的薪水相同,因此这两位员工都应该包含在结果中。
在子查询中使用 MAX 函数(功能)要找出薪水最高的员工,可以先用 MAX
函数找到最高薪水,再用子查询找出拿这个薪水的员工。
with Employees (EmployeeID, Name, Salary) as (
select 1, 'John', 5000
union all select 2, 'Jane', 7000
union all select 3, 'Bob', 4500
union all select 4, 'Alice', 9000
union all select 5, 'Mike', 9000
union all select 6, 'Sara', 8000
union all select 7, 'Tom', 6000
union all select 8, 'Lucy', 5500
union all select 9, 'Mary', 5820
union all select 10, 'Tom', 7890
)
select
a.*
from
Employees a
inner join (
select max(Salary) salary from Employees
) b
on a.Salary = b.Salary;
-- 或
select
a.*
from
Employees a
where
Salary = (select max(Salary) salary from Employees)
结果是:
取消透视这个例子来自Databricks SQL,但也可以在其他SQL引擎上运行。当你接收到以以下格式的数据时,将列中的值转换到行中对于数据建模很有帮助。
以下是一个示例查询:
WITH 数据 AS (productID, I2024, II2024, III2024, IV2024)
(
SELECT 1, 100, 123, 234, 4323
UNION ALL
SELECT 2, 123, 445, 33, 2212
UNION ALL
SELECT 3, 1222, 1223, 1232, 43232
UNION ALL
SELECT 4, 111, 223, 234, 213
UNION ALL
SELECT 5, 22332, 2323, 2334, 4342
)
SELECT *
FROM
数据 UNPIVOT INCLUDE NULLS
(
销售 FOR 季度 IN (I2024, II2024, III2024, IV2024)
);
结果是:
如果你的数据库不提供 UNPIVOT
功能,你可以通过使用 UNION
来达到同样的效果。
SELECT productID, I2024 AS 值(value), 'I2024' AS 季度(quarter) FROM 表 UNION ALL SELECT productID, II2024 AS 值(value), 'II2024' AS 季度(quarter) FROM 表 UNION ALL SELECT productID, III2024 AS 值(value), 'III2024' AS 季度(quarter) FROM 表 UNION ALL SELECT productID, IV2024 AS 值(value), 'IV2024' AS 季度(quarter) FROM 表
Replacing the SQL-specific terms and quarters as suggested:
SELECT productID, I2024 AS 值(value), '2024年第1季度' AS 季度(quarter) FROM 表 UNION ALL SELECT productID, II2024 AS 值(value), '2024年第2季度' AS 季度(quarter) FROM 表 UNION ALL SELECT productID, III2024 AS 值(value), '2024年第3季度' AS 季度(quarter) FROM 表 UNION ALL SELECT productID, IV2024 AS 值(value), '2024年第4季度' AS 季度(quarter) FROM 表
轴
与 UNPIVOT
相反的操作是 PIVOT
,它用于将行值转换为列的形式展示数据。这种技术在报表中展示数据时非常有用。
WITH data (年份, 季度, 地区, 数值) AS (
VALUES (2018, 1, '东部', 100),
(2018, 2, '东部', 20),
(2018, 3, '东部', 40),
(2018, 4, '东部', 40),
(2019, 1, '东部', 120),
(2019, 2, '东部', 110),
(2019, 3, '东部', 80),
(2019, 4, '东部', 60),
(2018, 1, '西部', 105),
(2018, 2, '西部', 25),
(2018, 3, '西部', 45),
(2018, 4, '西部', 45),
(2019, 1, '西部', 125),
(2019, 2, '西部', 115),
(2019, 3, '西部', 85),
(2019, 4, '西部', 65)
)
SELECT 年份, 地区, q1, q2, q3, q4
FROM data
PIVOT (SUM(数值) AS 销售额
FOR 季度
IN (1 AS q1, 2 AS q2, 3 AS q3, 4 AS q4))
结果 :
结果是怎么样的?
结果
对于 PIVOT
操作,我们可以使用 CASE WHEN
语句与 SUM
函数一起使用。这种做法更易于阅读,并且可以在不支持 PIVOT
操作的 SQL 引擎上使用。
SELECT 年份, 地区,
sum(case when 季度 = 1 then 值 end) AS 一季度,
sum(case when 季度 = 2 then 值 end) AS 二季度,
sum(case when 季度 = 3 then 值 end) AS 三季度,
sum(case when 季度 = 4 then 值 end) AS 四季度
FROM 数据
GROUP BY 年份, 地区;
结果为:
枢轴结果
行与行的比较:LAG 函数的使用The **LAG**
函数是一个窗口函数,它允许比较当前行与数据集中的前一行数据。这在诸如年对年同比和月对月同比等计算中特别有用,等等。
with 货币表 (日期, 价格, 货币代码) as (
select cast('2006-01-02' as date) ,3.2582, '美元'
UNION select cast('2006-01-03' as date) ,3.2488 , '美元'
UNION select cast('2006-01-04' as date) ,3.1858 , '美元'
UNION select cast('2006-01-05' as date) ,3.1416 , '美元'
UNION select cast('2006-01-06' as date) ,3.1507 , '美元'
UNION select cast('2006-01-09' as date) ,3.1228 , '美元'
UNION select cast('2006-01-10' as date) ,3.128 , '美元'
UNION select cast('2006-01-11' as date) ,3.1353 , '美元'
UNION select cast('2006-01-12' as date) ,3.1229 , '美元'
UNION select cast('2006-01-13' as date) ,3.1542 , '美元'
)
select
日期,
货币代码,
价格,
lag(价格) over (order by 日期) 前一天的价格,
(价格 - lag(价格) over (order by 日期)) / lag(价格) over (order by 日期) 变化率
from
货币表
我们期望的结果是,
LEAD 函数简介**LEAD**
函数的工作方式与 **LAG**
函数类似,但它将当前记录与下一条记录进行对比,而不是与前一条记录进行对比。此函数对于随时间变化的趋势分析或数据变化特别有用,例如识别趋势或数据中的变化。
WITH currency (日期, 价格, 货币) AS (
SELECT CAST('2006-01-02' AS date), 3.2582, 'USD'
UNION SELECT CAST('2006-01-03' AS date), 3.2488, 'USD'
UNION SELECT CAST('2006-01-04' AS date), 3.1858, 'USD'
UNION SELECT CAST('2006-01-05' AS date), 3.1416, 'USD'
UNION SELECT CAST('2006-01-06' AS date), 3.1507, 'USD'
UNION SELECT CAST('2006-01-09' AS date), 3.1228, 'USD'
UNION SELECT CAST('2006-01-10' AS date), 3.128, 'USD'
UNION SELECT CAST('2006-01-11' AS date), 3.1353, 'USD'
UNION SELECT CAST('2006-01-12' AS date), 3.1229, 'USD'
UNION SELECT CAST('2006-01-13' AS date), 3.1542, 'USD'
)
SELECT
日期,
货币,
价格,
LEAD(价格) OVER (ORDER BY 日期) 前一日价格 -- LEAD函数用于获取当前行的下一行数据,在这里表示获取前一日的价格
FROM
currency
我们预计的结果如下:
将数组转换成行数据在将数据存储为单个单元格的数组或需要特定转换时,例如 **EXPLODE**
函数可以非常有用,用于将数组元素拆分成单独的行。
在Databricks SQL中使用EXPLODE函数
由于 Databricks 不支持递归的公共表表达式 (CTEs),你可以通过结合 **SEQUENCE**
函数生成一系列值,并使用 **EXPLODE**
函数将数组拆分为行来创建一个日历表(calendar table)。
SELECT
date,
EXTRACT(YEAR FROM date) 年,
EXTRACT(MONTH FROM date) 月
FROM (
生成
EXPLODE(SEQUENCE(DATE '2024-01-01', DATE '2024-12-31', INTERVAL 1 DAY)) AS date
) 日历表
结果如下:
UNNEST:DuckDB和BigQuery在像DuckDB和BigQuery这样的数据库中,**UNNEST**
函数用于将数组或嵌套结构拆分成单独的行,类似于其他SQL引擎中的 **EXPLODE**
函数的功能。这种转换在处理复杂数据类型(如数组或嵌套的JSON结构)时尤其有用。
将数组 [1, 2, 3] 解构并选择为 qt 列
结果是:
NTILE (分组等级) NTILE 或 "分组等级" (fēnzǔ děngjí)The **NTILE**
函数是一个窗口函数,它将结果集中的行按照指定数量分成组或桶,确保每个组中的行数尽可能相等。此函数在各种分析任务中非常有用,例如将数据分成四分位数或获取特定的百分位数记录。
WITH Employees (EmployeeID, Name, Salary) AS (
SELECT 1, 'John', 5000
UNION ALL SELECT 2, 'Jane', 7000
UNION ALL SELECT 3, 'Bob', 4500
UNION ALL SELECT 4, 'Alice', 9000
UNION ALL SELECT 5, 'Mike', 12000
UNION ALL SELECT 6, 'Sara', 8000
UNION ALL SELECT 7, 'Tom', 6000
UNION ALL SELECT 8, 'Lucy', 5500
UNION ALL SELECT 9, 'Mary', 5820
UNION ALL SELECT 10, 'Tom', 7890
)
SELECT
EmployeeID,
Name,
Salary,
NTILE(10) OVER (ORDER BY Salary) AS 薪资分位数
FROM Employees
;
无具体内容,无需翻译。
并入**MERGE INTO**
命令允许你在目标表中根据源表的数据执行更新、插入和删除操作。这个命令很有用,因为它可以同步两个表,使目标表反映源表的更改。
使用数据库 demo;
CREATE TABLE silver.Employees
(
员工ID int,
名字 string,
姓氏 string,
经理ID int
);
CREATE TABLE silver.raw_Employees
(
员工ID int,
名字 string,
姓氏 string,
经理ID int
);
INSERT INTO Employees VALUES (1, 'Harper', 'Westbrook', NULL);
INSERT INTO Employees VALUES (2, 'Liam', 'Carrington', 1);
INSERT INTO Employees VALUES (3, 'Evelyn', 'Radcliffe', 1);
INSERT INTO Employees VALUES (4, 'Mason', 'Albright', 2);
INSERT INTO Employees VALUES (5, 'Isla', 'Whitman', 2);
INSERT INTO Employees VALUES (6, 'Noah', 'Sterling', 3);
INSERT INTO Employees VALUES (7, 'Ruby', 'Lennox', 3);
INSERT INTO Employees VALUES (8, 'Caleb', 'Winslow', 5);
INSERT INTO Employees VALUES (9, 'Avery', 'Sinclair', 6);
INSERT INTO Employees VALUES (10, 'Oliver', 'Beckett', 6);
INSERT INTO raw_Employees VALUES (1, 'Harper', 'Westbrook', NULL);
INSERT INTO raw_Employees VALUES (2, 'Liam', 'Carrington', 1);
INSERT INTO raw_Employees VALUES (3, 'Evelyn', 'Radcliffe', 1);
INSERT INTO raw_Employees VALUES (4, 'Mason', 'Albright', 2);
INSERT INTO raw_Employees VALUES (5, 'Isla', 'Whitman', 2);
INSERT INTO raw_Employees VALUES (6, 'Noah', 'Sterling', 3);
INSERT INTO raw_Employees VALUES (7, 'Ruby', 'Lennox', 3);
INSERT INTO raw_Employees VALUES (8, 'Caleb', 'Winslow', 5);
INSERT INTO raw_Employees VALUES (9, 'Avery', 'Sinclair', 6);
INSERT INTO raw_Employees VALUES (10, 'Oliver', 'Beckett', 6);
INSERT INTO raw_Employees VALUES (11, 'Avery', 'Sinclair', 6);
INSERT INTO raw_Employees VALUES (12, 'Oliver', 'Beckett', 6);
为了将源表中但目标表中不存在的所有行插入,你可以用下面的 **MERGE INTO**
语句:
MERGE INTO Employees AS target
USING raw_Employees as source
ON target.EmployeeID = source.EmployeeID
WHEN NOT MATCHED THEN INSERT *
要在目标表中插入新行,并根据源表更新现有行,您可以这样做:例如,您可以使用以下 **MERGE INTO**
语句:
MERGE INTO Employees AS target USING raw_Employees as source
ON target.EmployeeID = source.EmployeeID
-- 当源表和目标表的EmployeeID匹配时, 更新目标表的所有字段
WHEN MATCHED THEN UPDATE SET *
-- 当源表和目标表的EmployeeID不匹配时, 在目标表中插入新的记录
WHEN NOT MATCHED THEN INSERT *
检查这些表是否一样
在处理数据的过程中,尤其是在测试或调试代码时,我们经常需要比较表格。虽然对于小表格来说这相对来说比较简单,但比较拥有数百列的表格可能会极具挑战性。在这种情况下,**EXCEPT**
命令可以成为一个很有帮助的工具。
CREATE TABLE silver.Employees
(
EmployeeID int,
FirstName string,
LastName string,
ManagerID int
);
CREATE TABLE silver.raw_Employees
(
EmployeeID int,
FirstName string,
LastName string,
ManagerID int
);
INSERT INTO Employees VALUES (1, 'Harper', 'Westbrook', NULL);
INSERT INTO Employees VALUES (2, 'Liam', 'Carrington', 1);
INSERT INTO Employees VALUES (3, 'Evelyn', 'Radcliffe', 1);
INSERT INTO Employees VALUES (4, 'Mason', 'Albright', 2);
INSERT INTO Employees VALUES (5, 'Isla', 'Whitman', 2);
INSERT INTO Employees VALUES (6, 'Noah', 'Sterling', 3);
INSERT INTO Employees VALUES (7, 'Ruby', 'Lennox', 3);
INSERT INTO Employees VALUES (8, 'Caleb', 'Winslow', 5);
INSERT INTO Employees VALUES (9, 'Avery', 'Sinclair', 6);
INSERT INTO Employees VALUES (10, 'Oliver', 'Beckett', 6);
INSERT INTO raw_Employees VALUES (1, 'Harper', 'Westbrook', NULL);
INSERT INTO raw_Employees VALUES (2, 'Liam', 'Carrington', 1);
INSERT INTO raw_Employees VALUES (3, 'Evelyn', 'Radcliffe', 1);
INSERT INTO raw_Employees VALUES (4, 'Mason', 'Albright', 2);
INSERT INTO raw_Employees VALUES (5, 'Isla', 'Whitman', 2);
INSERT INTO raw_Employees VALUES (6, 'Noah', 'Sterling', 3);
INSERT INTO raw_Employees VALUES (7, 'Ruby', 'Lennox', NULL);
INSERT INTO raw_Employees VALUES (8, 'Caleb', 'Winslow', 5);
INSERT INTO raw_Employees VALUES (9, 'Avery', 'Sinclair', 6);
INSERT INTO raw_Employees VALUES (10, 'Oliver', 'Beckett', 6);
试试代码:
选择 silver.Employees 表中的所有列
排除
选择 silver.raw_Employees 表中的所有列
运行此命令后,结果将显示两个表之间不匹配的记录。例如,如果 raw_Employees
中某行的 ManagerID
为 NULL
,这种差异会被显示出来。
结果应为:
谢谢您的阅读!如果你觉得这篇文章有帮助或有启发,我邀请你通过在LinkedIn上点个赞并点个“赞”按钮来表达你的赞赏。你的支持非常宝贵。