调试 SQL 查询结果中的缺失数据
当您的查询返回缺少行或列的数据时该怎么办。
您的数据在哪里丢失了?
缺失的行
在开始之前,请确保您了解源表或嵌套查询的模式。
- 检查您的源表或嵌套查询是否缺少行。
- 查看下表,看看您是否因为连接类型而缺少行。
-
检查
ON
子句中的连接条件。例如-- The join condition below will filter out -- all transactions from the Orders table -- where the product category is 'Gizmo'. SELECT * FROM orders o JOIN products p ON o.product_id = p.id AND p.category <> 'Gizmo';
-
检查您的
WHERE
子句是否与您的JOIN
子句交互。例如-- The WHERE clause below will filter out -- all transactions from the Orders table -- where the product category is 'Gizmo'. SELECT * FROM orders o JOIN products p ON o.product_id = p.id AND p.category = 'Gizmo' WHERE p.category <> 'Gizmo'
- 如果您想添加行到查询结果中以填充空、零或
NULL
的数据,请转到如何填充缺失报告日期的数据。
连接如何过滤掉不匹配的行
连接类型 | 如果连接条件不满足 |
---|---|
A INNER JOIN B | A和B中的行都被过滤掉。 |
A LEFT JOIN B | B中的行被过滤掉。 |
B LEFT JOIN A | A中的行被过滤掉。 |
A OUTER JOIN B | A和B中的行都被过滤掉。 |
A FULL JOIN B | 没有行被过滤掉。 |
解释
您的JOIN
子句中表的顺序会影响查询返回的行。
例如,当您编写LEFT JOIN
时,在查询中位于LEFT JOIN
子句之前的表是“左侧”表。如果“右侧”表(位于LEFT JOIN
子句之后的表)的行不满足ON
子句中的连接条件,它们将被过滤掉。
查询的执行顺序可能会以您意想不到的方式组合您的连接条件和WHERE
子句。
延伸阅读
如何填充缺失报告日期的数据
如果您的源表或嵌套查询只存储发生过事件的日期行,您将得到缺少报告日期结果。
例如,示例数据库中的Orders
表只存储订单创建日期的行。它不存储没有订单活动的日期的任何行。
-- The query below calculates the total sales
-- for each day that had at least one order.
-- For example, note that there is no row
-- in the query results for May 5, 2016.
SELECT
DATE_TRUNC('day', o.created_at)::date AS "order_created_date",
SUM(p.price) AS "total_sales"
FROM
orders o
JOIN products p ON o.product_id = p.id
WHERE
o.created_at BETWEEN'2016-05-01'::date
AND '2016-05-30'::date
GROUP BY
"order_created_date"
ORDER BY
"order_created_date" ASC;
如果您想要下表所示的结果,您需要从包含所有所需日期(或任何其他序列)的表或列开始您的JOIN
。询问您的数据库管理员是否有可用于此目的的表。
+--------------------+-------------+
| report_date | total_sales |
+--------------------+-------------+
| May 4, 2016 | 98.78 |
+--------------------+-------------+
| May 5, 2016 | 0.00 |
+--------------------+-------------+
| May 6, 2016 | 87.29 |
+--------------------+-------------+
| May 7, 2016 | 0.00 |
+--------------------+-------------+
| May 8, 2016 | 81.61 |
+--------------------+-------------+
如果您的SQL方言支持GENERATE_SERIES
函数,您可以创建一个临时列来存储您的报告日期。
-- The query below calculates the total sales
-- for every day in the report period,
-- including days with 0 orders.
-- The date_series CTE generates one row
-- per date that you want in your final result.
WITH date_series AS (
SELECT
*
FROM
GENERATE_SERIES('2016-05-01'::date, '2020-05-30'::date, '1 day'::interval) report_date
)
-- The fact_orders CTE generates the total sales
-- for each date that had an order.
, fact_orders AS (
SELECT
DATE_TRUNC('day', o.created_at)::date AS "order_created_date",
SUM(p.price) AS "total_sales"
FROM
orders o
JOIN products p ON o.product_id = p.id
GROUP BY
"order_created_date"
ORDER BY
"order_created_date" ASC
)
-- The main query joins the two CTEs together
-- and uses the COALESCE function to fill in the dates
-- where there were no orders (i.e. a total sales value of 0).
SELECT
d.report_date,
o.order_created_date,
COALESCE(o.total_sales, 0) AS total_sales
FROM
date_series d
LEFT JOIN fact_orders o ON d.date = o.order_created_date
;
缺失的列
- 如果您正在连接数据,请检查您的
SELECT
语句是否包含您想要的列。- 您是否使用了正确的表别名?
- 您的
FROM
子句中是否缺少表?
- 按照调试SQL逻辑中的步骤1,检查您的源表或查询结果是否缺少列。
- 了解更多关于查询结果意外的常见原因。
您有其他问题吗?
您还卡住了吗?
搜索或咨询 Metabase 社区。