【问题标题】:Find first available value that doesn't exist查找不存在的第一个可用值
【发布时间】:2021-01-16 12:13:46
【问题描述】:

我想为书籍章节创建表,其中 pk 将是 book_idchapter_internal_number。我不确定如何为新章节插入找到下一个免费的chapter_internal_number 值(章节可以删除,它的chapter_internal_number 值应该被重用)。

如何找到书籍的第一章内部编号可用价值?可用值是在 ASC 顺序中不存在的下一个值。

表书_章节:

|    pk   |           pk            |
| book_id | chapter_internal_number |
| 1       |          1              |
| 1       |          2              |
| 1       |          5              |
| 2       |          1              |
| 2       |          2              |
| 2       |          3              |

预期:

  • 对于 book_id=1 是 3
  • 对于 book_id=2 是 4

【问题讨论】:

    标签: sql postgresql subquery greatest-n-per-group window-functions


    【解决方案1】:

    基本上,您需要每本书的章节编号中的第一个空白。我认为您不需要generate_series()。您可以使用lead() 将当前章节与下一章节进行比较:

    select book_id, min(chapter_internal_number) + 1
    from (
        select bc.*, 
            lead(chapter_internal_number) over(partition by book_id order by chapter_internal_number) lead_chapter_internal_number
        from book_chapter bc
    ) bc
    where lead_chapter_internal_number is distinct from chapter_internal_number + 1
    group by book_id
    

    这似乎是表达您的查询的最自然的方式,我怀疑用generate_series() 枚举所有可能的值应该更有效(我很想知道这两种解决方案相对于大型数据集的表现如何)。

    我们也可以在外部查询中使用distinct on 而不是聚合:

    select distinct on (book_id) book_id, chapter_internal_number + 1
    from (
        select bc.*, 
            lead(chapter_internal_number) over(partition by book_id order by chapter_internal_number) lead_chapter_internal_number
        from book_chapter bc
    ) bc
    where lead_chapter_internal_number is distinct from chapter_internal_number + 1
    order by book_id, chapter_internal_number
    

    【讨论】:

    • 谢谢,这看起来更简单了,你能不能也添加插入行语句?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多