查找 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 列

在运行 SELECT 语句时,日期列中的空白值返回为 1900/01/01

查找每个 ID 的特定日期之前的最大日期和特定日期之后的最小日期 [关闭]