查找 ID 列中的空白 + 选择上一个/下一个日期列
Posted
技术标签:
【中文标题】查找 ID 列中的空白 + 选择上一个/下一个日期列【英文标题】:Find the gap in ID column + select the prev/next date column 【发布时间】:2016-10-24 09:59:04 【问题描述】:我们有一个带有ID
autoincrement 列的表,其中有间隙。每行还有一个created
日期。
我们正在尝试为每个间隙 ID(缺失的 ID)找出表格中可用的上一个/下一个日期。
我们已经构建了一个用于识别间隙的 SQL(来自 here 的解决方案),所以我将它们缓存在一个表中,但是从这里如何找到覆盖原始间隙的上一个/下一个 created
日期表。
输入:
+----+------------+
| 84 | 1443728132 |
| 91 | 1443728489 |
| 93 | 1443729058 |
| 94 | 1443729200 |
+----+------------+
输出
+--------+------------+------------+
| gap_id | prev_dt | next_dt |
+--------+------------+------------+
| 85 | 1443728132 | 1443728489 |
| 86 | 1443728132 | 1443728489 |
| 87 | 1443728132 | 1443728489 |
| 88 | 1443728132 | 1443728489 |
| 89 | 1443728132 | 1443728489 |
| 90 | 1443728132 | 1443728489 |
| 92 | 1443728489 | 1443729058 |
+--------+------------+------------+
我最终选择了Google BigQuery。
【问题讨论】:
您使用的是哪个 DBMS? 没关系,我们可以迁移到首选的解决方案,因为我们的系统中有很多 mysql、Microsoft、BigQuery。 针对 MySQL 有限功能的解决方案与针对支持 modern SQL的 DBMS 的解决方案看起来非常不同 我们可以适应,我们并不是要在所有系统中找到解决方案,而是要找到一个系统更容易的解决方案 @Pentium10 。 . . 在问题中添加数据样本,而不是作为要下载的文件。还包括期望的结果。 【参考方案1】:我建议将结果分组为范围:
select min(id + 1) as first_missing_id,
(next_id - 1) as last_missing_id,
next_dte
from (select t.*,
lead(id) over (order by id) as next_id,
lead(dte) over (order by id) as next_dte
from t
) t
where next_id <> id + 1
group by next_id, next_dte;
获取个人 ID 很棘手。毕竟,如果您有 1、1000000、1000000000,那么您可能会生成很多行。
【讨论】:
结果已经从每个范围的下边缘构建。无需聚合(next_id 是唯一的)【参考方案2】:应该适用于 MySQL 以外的大多数数据库
select *
from (select lag (id) over (order by id) + 1 as gap_start
,id - 1 as gap_end
,lag (dt) over (order by id) as dt_before_gap
,dt as dt_after_gap
,case when lag (id) over (order by id) + 1 <> id then 'Y' end as is_gap
from t
) t
where is_gap = 'Y'
;
【讨论】:
【参考方案3】:对于 BigQuery 标准 SQL
WITH yourTable AS (
SELECT 84 AS id, 1443728132 AS dt UNION ALL
SELECT 91 AS id, 1443728489 AS dt UNION ALL
SELECT 93 AS id, 1443729058 AS dt UNION ALL
SELECT 94 AS id, 1443729200 AS dt
),
nums AS (
SELECT num
FROM UNNEST(GENERATE_ARRAY((SELECT MIN(id) FROM YourTable), (SELECT MAX(id) FROM YourTable))) AS num
),
gaps AS (
SELECT
LAG (id) OVER (ORDER BY id) + 1 AS gap_start,
id - 1 AS gap_end,
LAG (dt) OVER (ORDER BY id) AS prev_dt,
dt AS next_dt,
CASE
WHEN LAG (id) OVER (ORDER BY id) + 1 <> id THEN 'Y'
END AS is_gap
FROM
yourTable
)
SELECT num as gap_id, prev_dt, next_dt
FROM gaps JOIN nums
ON num BETWEEN gap_start AND gap_end
WHERE is_gap = 'Y'
ORDER BY num
输出:
gap_id prev_dt next_dt
85 1443728132 1443728489
86 1443728132 1443728489
87 1443728132 1443728489
88 1443728132 1443728489
89 1443728132 1443728489
90 1443728132 1443728489
92 1443728489 1443729058
【讨论】:
不幸的是,我不得不使用其他东西,因为GENERATE_ARRAY
最多只能处理 100 万个条目,而且我还有很多条目要处理。由于order by
,我的资源也用完了,所以我不得不删除它,并使用更多的静态表来避免任何交叉连接。
当然 :o) 请注意 - ORDER BY
根本不是逻辑的一部分 - 只需将其删除 - 在示例中仅用于演示目的!
如果你能在这里分享你的最终解决方案会很棒
我也使用 BQ cli 构建了一个大型静态表,运行多个 GENERATE_ARRAY(i,j)
查询,然后删除 order by,并将查询拆分为多个部分以避免资源耗尽。
GENERATE_ARRAY
中一百万个元素的限制是相当随意的(我们不想让它太容易以“超出资源”而告终)。你最终需要多少元素?我们可以考虑提高未来的上限。以上是关于查找 ID 列中的空白 + 选择上一个/下一个日期列的主要内容,如果未能解决你的问题,请参考以下文章
如何按 ID 分组并查找日期中的空白以确定 Alteryx 中的开始和结束日期?
如果 A 列中的单元格为空白,则针对不同工作表中的数据集查找 B 列