从布尔列构建数组

lur*_*urv 2 postgresql array unpivot

我有诸如role1role2role3等列。它们都是布尔值。

\n\n

我想在此表上创建一个视图,该视图具有类型为 的角色列text[]。如果有列TRUE, FALSE, TRUE,则视图将包含["role1", "role3"].

\n\n

有什么好的方法可以做到这一点,并且不会爆炸成大量的CASE WHEN\xc2\xb4s 吗?澄清一下,我可以使用 O(n) CASE WHEN,但不能使用 O(2^n) ,这是目前似乎需要的。:)

\n

Erw*_*ter 6

我建议VALUES在横向子查询中使用表达式。

SELECT t.id, a.roles
FROM   tbl t
CROSS  JOIN LATERAL (
   SELECT ARRAY(
      SELECT col
      FROM  (
         VALUES
            ('role1', role1) -- eligible columns
          , ('role2', role2)
          , ('role3', role3)
         ) x(col, val)
      WHERE  val
     )
  ) a(roles);
Run Code Online (Sandbox Code Playgroud)

这将列“逆透视”为行,因此我们可以处理一组而不是一行。

正如a_horse 所演示的json( b) 具有足够的通用性,足以涵盖此任务。boolean在处理所有列时,您无需拼写出符合条件的列。但无论如何,您似乎都必须拼出符合条件的列。

细微的差别:对于“无限定值”( {}),这会返回一个空数组,而 a_horse 的查询也会返回NULL相同的值。

由于以下三个原因,这应该要快得多:

  1. 首先只处理符合条件的列。尤其与许多附加的(可能很大?)列相关。
  2. 涉及更少的来回转换,并且谓词尽可能便宜。
  3. ARRAY 构造函数比array_agg(). 看:

或者,更简单:CASE用 . 连接的普通表达式concat_ws()。如果字符串足够好:

SELECT t.id
     , concat_ws(','
               , CASE WHEN role1 THEN 'role1' END -- eligible columns
               , CASE WHEN role2 THEN 'role2' END
               , CASE WHEN role3 THEN 'role3' END) AS roles_string
FROM   tbl t;
Run Code Online (Sandbox Code Playgroud)

应该是最快的解决方案。而且没有那么冗长。看:

或者获取与上面相同的数组:

SELECT t.id
     , string_to_array(
          concat_ws(
             ','
           , CASE WHEN role1 THEN 'role1' END -- eligible columns
           , CASE WHEN role2 THEN 'role2' END
           , CASE WHEN role3 THEN 'role3' END)
        , ',') AS roles
FROM   tbl t;
Run Code Online (Sandbox Code Playgroud)

我们还可以从系统目录动态生成符合条件的列的列表。(如果您根本不想拼出列。)

或者缩小到json( b) 技术的合格列,以尽早消除可能昂贵的噪音。看:

db<>在这里摆弄- 包括。以上所有内容、a_horse 的 jsonb 查询以及一些变体