编写SQL对数据进行清洗

在数据分析和数据挖掘的过程中,数据清洗和预处理是至关重要的一步。本文将介绍各种常用的Lakehouse SQL数据清洗方法,帮助您更好地理解和应用这些方法。

构建环境

导航到Lakehouse Studio开发->任务,单击“+”新建一个SQL任务(以下两种方式都在同一个任务里实现)。

新建两个SQL任务(如下图所示),然后从GitHub获取代码并将SQL代码复制到两个任务里。

然后逐一运行每个SQL,观察结果。

以下是各个步骤的说明。

构建实验用的Schema和计算集群

-- Data_Clean virtual cluster
CREATE VCLUSTER IF NOT EXISTS Data_Clean
   VCLUSTER_SIZE = XSMALL
   VCLUSTER_TYPE = GENERAL
   AUTO_SUSPEND_IN_SECOND = 60
   AUTO_RESUME = TRUE
   COMMENT  'Data_Clean VCLUSTER for test';

-- Use our VCLUSTER
USE VCLUSTER Data_Clean;

-- Create and Use SCHEMA
CREATE SCHEMA IF NOT EXISTS  Data_Clean;
USE SCHEMA Data_Clean;

将IDE里每个任务的schema和集群设置为新创建的:

创建示例表并插入脏数据

首先,我们需要创建一个示例表,并插入一些包含脏数据的示例数据,以便在接下来的步骤中进行演示。

-- 创建名为 "sales_data" 的示例表
CREATE TABLE sales_data (
    id INT,
    sale_date DATE,
    customer_id INT,
    product_id VARCHAR(50),
    quantity INT,
    price DECIMAL(10, 2),
    total_amount DECIMAL(10, 2),
    region VARCHAR(50)
);

-- 插入20行包含脏数据的示例数据
INSERT INTO sales_data (id, sale_date, customer_id, product_id, quantity, price, total_amount, region) VALUES
(1, '2025-01-01', 101, '201A', 5, 100.00, 500.00, 'North'),
(2, '2025-01-02', 102, '202', 3, 150.00, 450.00, 'East'),
(3, '2025-01-03', NULL, '203', 8, 200.00, 1600.00, 'South'), -- 缺失customer_id
(4, '2025-01-04', 104, '204', -10, 50.00, 500.00, 'West'), -- quantity负数
(5, '2025-01-05', 105, '201@#', 7, 75.00, 525.00, 'North'), -- product_id包含特殊字符
(6, '2025-01-06', 106, '202', 9, NULL, 1080.00, 'East'), -- 缺失price
(7, '2025-01-07', 107, '203', 4, 60.00, 240.00, 'South'),
(8, '2025-01-08', 108, '204', 6, 80.00, 480.00, ''), -- region为空
(9, '2025-01-09', 109, '201', 2, 110.00, 220.00, 'North'),
(10, '2025-01-10', 110, '202', 1, 130.00, 130.00, 'East'),
(11, '2025-01-11', 111, '203', 5, 140.00, 700.00, 'South'),
(12, '2025-01-12', 112, '204', 3, 70.00, 210.00, 'NULL'), -- region包含非法字符
(13, '2025-01-13', 113, '201', 8, 160.00, 1280.00, 'North'),
(14, '2025-01-14', 114, '202A', 6, 90.00, 540.00, 'East'), -- product_id包含特殊字符
(15, '2025-01-15', 115, '203', 7, 170.00, 1190.00, 'South'),
(16, '2025-01-16', 116, '204', 4, 180.00, 720.00, 'West'),
(17, '2025-01-17', 117, '201', 5, 85.00, 425.00, 'North'),
(18, '2025-01-18', 118, '202', 9, 190.00, 1710.00, 'East'),
(19, '2025-01-19', 119, '203', 2, 200.00, 400.00, 'South'),
(20, '2025-01-20', 120, '204', -1, 210.00, 210.00, 'West'); -- quantity负数

脏数据问题和处理方法说明

  1. 缺失值

    • 示例: 第3行的customer_id缺失。
    • 问题: 缺失值会导致分析不完整或错误。
    • 处理: 使用COALESCEIFNULL填充默认值,如0
  2. 负数值

    • 示例: 第4行和第20行的quantity为负数。
    • 问题: 负数值在某些场景下是不合理的,如销售数量。
    • 处理: 使用CASE语句将负数值转换为合理值。
  3. 特殊字符

    • 示例: 第5行和第14行的product_id包含特殊字符。
    • 问题: 特殊字符可能导致数据解析错误。
    • 处理: 使用REGEXP_REPLACE移除特殊字符。
  4. 缺失字段

    • 示例: 第6行的price缺失。
    • 问题: 缺失字段会导致数据不完整。
    • 处理: 使用COALESCEIFNULL填充默认值。
  5. 空字符串

    • 示例: 第8行的region为空。
    • 问题: 空字符串会导致数据解析不准确。
    • 处理: 使用TRIM函数删除空白值。
  6. 非法字符

    • 示例: 第12行的region包含非法字符。
    • 问题: 非法字符会导致数据解析错误。
    • 处理: 使用REGEXP_REPLACE移除非法字符。

通过上述方法处理这些脏数据,可以显著提高数据质量,为后续的数据分析和挖掘提供更可靠的基础。

处理缺失值

说明

缺失值是数据清洗中常见的问题。它们会导致数据分析结果不准确。可以使用 COALESCE 函数、IFNULL 函数或者 CASE 语句填充默认值,或替换缺失值。在实际项目中,处理缺失值常用于确保关键字段不为空,保证数据的完整性。

实现

-- 使用 COALESCE 填充默认值
SELECT id, sale_date, COALESCE(customer_id, 0) AS customer_id, product_id, quantity, price, COALESCE(total_amount, 0) AS total_amount, region FROM sales_data;

-- 使用 IFNULL 填充默认值
SELECT id, sale_date, IFNULL(customer_id, 0) AS customer_id, product_id, quantity, price, IFNULL(total_amount, 0) AS total_amount, region FROM sales_data;

-- 使用 CASE 语句处理缺失值
SELECT id, 
       CASE 
           WHEN sale_date IS NULL THEN '2025-01-01'
           ELSE sale_date
       END AS sale_date,
       customer_id, 
       product_id, 
       quantity, 
       price, 
       total_amount, 
       region 
FROM sales_data;

移除特殊字符

说明

特殊字符会影响数据的分析,可以使用 REGEXP_REPLACE 函数来移除这些字符。在实际项目中,移除特殊字符常用于清理文本字段中的噪音字符,使数据更加整洁和规范。

实现

-- 移除特殊字符
SELECT id, sale_date, customer_id, 
       REGEXP_REPLACE(product_id, '[a-zA-Z0-9]', '') AS cleaned_product_id,
       quantity, 
       price, 
       total_amount, 
       region
FROM sales_data;

转换数据类型

说明

有时候需要将数据从一种类型转换为另一种类型,例如将字符串转换为日期类型。数据类型的转换能够保证数据的一致性和准确性。在实际项目中,常用于标准化数据格式,如日期、金额等。

实现

-- 将字符串转换为日期
SELECT id, CAST(sale_date AS DATE) AS sale_date, 
    customer_id, product_id, quantity, 
    CAST(price AS DECIMAL(10, 2)) AS price, 
    CAST(total_amount AS DECIMAL(10, 2)) AS total_amount, region 
FROM sales_data;

删除空格

说明

在数据清洗过程中,字符串前后的空格会导致数据分析结果的不准确。我们可以使用 TRIM 函数删除空格。在实际项目中,删除空格常用于清理包含多余空格的文本字段。

实现

-- 删除空白值
SELECT id, 
       TRIM(sale_date) AS sale_date, 
       customer_id, 
       product_id, 
       quantity, 
       price, 
       total_amount, 
       TRIM(region) AS region
FROM sales_data;

转换大小写

说明

为了统一数据格式,可以将文本字段转换为小写或大写。在实际项目中,转换大小写常用于确保数据的一致性,如在客户名称、产品名称等字段中。

实现

-- 将区域字段转换为小写
SELECT id, 
       sale_date, 
       customer_id, 
       product_id, 
       quantity, 
       price, 
       total_amount, 
       LOWER(region) AS region
FROM sales_data;

删除异常值

说明

异常值可能会影响数据分析的结果,使用 DELETE 语句可以删除这些记录。在实际项目中,删除异常值常用于剔除极端或错误的数据,以保证分析结果的准确性。

实现

-- 删除销售金额小于50的记录DELETE FROM sales_data WHERE total_amount < -5000;

去重

说明

在数据集中,重复记录会影响数据分析的准确性。我们可以使用 DISTINCT 或者 ROW_NUMBER() 函数来去除重复记录。在实际项目中,去重操作常用于合并多个数据源或清理历史数据时。

实现

-- 使用 DISTINCT 去重
SELECT DISTINCT customer_id, product_id, region FROM sales_data;

-- 使用 ROW_NUMBER() 去重
WITH RowNumCTE AS (
    SELECT *,
           ROW_NUMBER() OVER(PARTITION BY customer_id, product_id, region ORDER BY id) AS row_num
    FROM sales_data
)
SELECT id, sale_date, customer_id, product_id, quantity, price, total_amount, region
FROM RowNumCTE
WHERE row_num = 1;

数据分组和聚合

说明

通过分组和聚合,可以生成汇总报告,了解数据的整体情况。分组和聚合操作可以帮助我们发现数据中的模式和趋势。在实际项目中,常用于统计、分析数据,如计算销售总额、平均值等。

实现

-- 按区域分组计算总销售额
SELECT region, SUM(total_amount) AS total_sales FROM sales_data GROUP BY region;

-- 按产品分组计算总销售量
SELECT product_id, SUM(quantity) AS total_quantity FROM sales_data GROUP BY product_id;

数据筛选

说明

使用 WHERE 子句筛选出符合特定条件的数据。在实际项目中,数据筛选常用于提取感兴趣的数据子集,如筛选出高价值客户、特定时间段的销售数据等。

实现

-- 筛选出销售金额大于500的记录
SELECT * FROM sales_data WHERE total_amount > 500;

数据排序

说明

排序可以帮助我们按特定顺序查看数据,发现数据中的模式和趋势。在实际项目中,排序常用于数据展示、报告生成等场景。

实现

-- 按销售金额排序
SELECT * FROM sales_data ORDER BY total_amount DESC;

合并列数据

说明

在某些情况下,我们需要将多个列的数据合并为一列。在实际项目中,合并列数据常用于生成综合信息字段,如完整的地址、姓名等。

实现

-- 合并产品ID和区域字段
SELECT id,       sale_date,       customer_id,       product_id || '-' || region AS combined_field,       quantity,       price,       total_amountFROM sales_data;

合并数据

说明

使用 UNION 操作将多个结果集合并在一起,形成一个完整的结果集。在实际项目中,合并数据常用于将多个查询结果整合在一起,形成统一的分析数据集。

实现

-- 合并两个结果集
SELECT id, sale_date, customer_id, product_id, quantity, price, total_amount, region FROM sales_data
UNION
SELECT id, sale_date, customer_id, product_id, quantity, price, total_amount, region FROM another_sales_data;

通过以上的SQL数据清洗和预处理技术,您可以有效地处理和转换数据,为后续的数据分析和挖掘奠定坚实的基础。数据清洗不仅能提高数据质量,还能为数据分析带来更多的准确性和可靠性。

数据清洗SQL函数列表

以下是常用的SQL数据清洗函数列表:

  1. 处理缺失值

    • COALESCE(): 用于将NULL值替换为指定的默认值。
    • IFNULL(): 类似于COALESCE(),用于将NULL值替换为指定的默认值。
    • CASE: 用于根据特定条件处理缺失值。
  2. 移除特殊字符

    • REGEXP_REPLACE(): 用于使用正则表达式替换文本中的特殊字符。
  3. 转换数据类型

    • CAST(): 用于将数据从一种类型转换为另一种类型。
  4. 删除空白值

    • TRIM(): 用于删除字符串中的空白字符。
  5. 转换大小写

    • LOWER(): 将文本转换为小写。
    • UPPER(): 将文本转换为大写。
  6. 删除异常值

    • DELETE: 用于删除不符合条件的记录。
  7. 去重

    • DISTINCT: 用于去除结果集中的重复行。
    • ROW_NUMBER(): 用于对结果集中的每一行分配唯一的行号。
  8. 数据分组和聚合

    • GROUP BY: 用于将结果集按一个或多个列进行分组。
    • SUM(): 用于计算指定列的总和。
    • AVG(): 用于计算指定列的平均值。
    • COUNT(): 用于计算指定列的记录数。
  9. 数据筛选

    • WHERE: 用于筛选符合特定条件的记录。
  10. 数据排序

    • ORDER BY: 用于对结果集进行排序。
  11. 数据联合

    • JOIN: 用于将两个或多个表联合起来,形成一个完整的数据视图。
  12. 合并列数据

    • CONCAT(): 用于将多个列的数据合并为一个列。
  13. 合并数据

    • UNION: 用于将多个结果集合并在一起。

联系我们
预约咨询
微信咨询
电话咨询