【问题标题】:Return true if all column values are true如果所有列值都为真,则返回真
【发布时间】:2012-10-12 11:32:51
【问题描述】:

在 PostgreSQL 中是否有一种更快的方法来本质上对多行执行 if 操作?

假设我有一张桌子

ticket | row | archived
1      | 1   | true
1      | 2   | true
1      | 3   | true
2      | 1   | false
2      | 2   | true

有什么方法可以在 ticket = 的列下方做一个 if 语句? 因此,其中票 = 1 将是正确的,因为

true && true && true = true

其中ticket = 2 会是假的,因为

false && true = false

或者我应该坚持

SELECT ( (SELECT COUNT(*) FROM table WHERE ticket = 1)
       = (SELECT COUNT(*) FROM table WHERE ticket = 1 AND archived = true) )

【问题讨论】:

    标签: sql postgresql aggregate-functions exists boolean-logic


    【解决方案1】:

    聚合函数bool_and()

    简单、简短、清晰:

    SELECT bool_and(archived)
    FROM   tbl
    WHERE  ticket = 1;
    

    The manual:

    如果所有输入值都为真,则为真,否则为假

    子查询表达式EXISTS

    点赞@Mike provided

    更快。但是您必须另外检查是否存在任何带有ticket = 1 的行,否则您将得到不存在的票证的错误结果:

    SELECT EXISTS (SELECT 1 FROM tbl WHERE ticket=1)
           AND NOT
           EXISTS (SELECT 1 FROM tbl WHERE ticket=1 AND archived = FALSE);
    

    指数

    两种形式都可以并且将使用如下索引:

    CREATE index tbl_ticket_idx ON tbl (ticket);
    

    .. 这使得两者都快,但EXISTS 查询更快,因为一旦找到第一个匹配行,此表单就会停止扫描。这两个查询几乎没有任何区别,每张票只有几行,但每张票有很多行实质性差异。

    要使用 pg 9.2 中的仅索引扫描,您需要multi-column index 的形式:

    CREATE index tbl_ticket_archived_idx ON tbl (ticket, archived);
    

    这个更好any case大多数情况下和任何版本的PostgreSQL。由于data alignment,在索引中的integer 中添加boolean 根本不会使索引增长。几乎不花任何钱就能获得额外的好处。

    但是,索引列会阻止 HOT(仅堆元组)更新。例如,UPDATE 仅更改列 archived。如果该列未被任何索引(以任何方式)使用,则该行可以被热更新。否则不能走这条捷径。更多关于热门更新:

    这一切都取决于您的实际工作量。

    【讨论】:

    • 绝对是一个干净的解决方案!好奇性能如何,它能否利用 9.2 中的仅索引扫描?
    • @Mike:我挖得更深一些,进行了一些测试,并在我的答案中添加了一些关于索引和性能的信息。
    • @MikeChristensen 感谢您抽出宝贵的时间来回答!不过,我接受了 Erwin 的回答,因为更短的代码在我的查询中会更好!性能影响不应该太大,我不希望这个查询在每张票上运行超过几行。谢谢大家!
    • @mouckatron:我添加了一些关于 HOT 更新的内容。如果您有很多 UPDATEs,您可能会感兴趣。
    • @ErwinBrandstetter 我总是对您对 Postgres 的了解印象深刻。到目前为止,我已经对你的几十个答案投了赞成票。
    【解决方案2】:

    比如:

    select not exists (select 1 from table where ticket=1 and not archived)
    

    我认为这可能比比较计数更有利,因为 count may or may not use an index 并且您真正需要知道的是该票是否存在 任何 FALSE 行。我认为仅在 ticket 上创建部分索引可能会非常快。

    SQL Fiddle

    【讨论】:

    • Count 不会使用索引如果它是 9.2 之前的 PostgreSQL 版本。最近才知道。
    • @JayC:当然 count() 可以使用索引。 select count(*) from foo where some_col = 1 可以在 some_col 上使用索引,前提是它不会返回太多行。 count() 将不会使用索引,如果您正在计算表中的 所有 行(没有任何限制)
    • @a_horse_with_no_name - 哦,谢谢你清理它!在this 最近的问题之后,我有点好奇,我看到你也发表了评论。
    • @a_horse_with_no_name:你是对的;我不应该让迈克迷惑我;-)
    【解决方案3】:
    select not false = any (
            select archived
            from foo
            where ticket = 1
        )
    

    SQL Fiddle

    【讨论】:

      猜你喜欢
      • 2021-10-15
      • 2022-11-25
      • 1970-01-01
      • 2016-05-03
      • 1970-01-01
      • 2018-07-29
      • 2015-04-27
      • 2020-06-24
      • 2017-07-28
      相关资源
      最近更新 更多