将aclitem数组转换为多行redshift

时间:2018-08-12 14:09:48

标签: amazon-redshift amazon-redshift-spectrum

我有一个数组,列值为

{james = UC / james,adam = C / james,chris = U C / james,john = U / james}

以上列的值不是json。它们是以下形式的字符串:

{ username=privilegestring/grantor } 

如何将上面的列转换为多行

1 个答案:

答案 0 :(得分:0)

编辑#3:
通过CTE pg_catalog 将查询更新为专门针对pg_catalog.pg_namespace的ACL权限授予。当前,此CTE已在where子句中进行过滤以选择单个名称空间名称('avengers');如果要从多个名称空间名称中进行选择,则应该可以将它们直接添加到此CTE的WHERE子句中,或者在需要所有名称空间名称的情况下,请完全删除该子句。 < / p>

同样值得注意的是,您将需要扩展access_privilege_types中的case语句来处理所有权限情况:“ r”,“ w”,“ a”,“ d”和'x',分别用于SELECTUPDATEINSERTDELETEREFERENCE

编辑#2:
下面的查询的最终发布版本将以所需的格式为您提供所需的数据。如果当前所指定的两个以上,则需要在CTE * access_privilege_types *中扩展case语句。显然,您还需要在查询中替换表名,等等。如果您遇到任何麻烦,请告诉我,我们将在必要时为您提供帮助。

编辑#1:
能够验证此查询在Redshift中是否有效。更新了查询,以按授权人和所有者分开单独的行。当前版本尚未按行细分个人权限-今晚晚些时候看一下我是否也能正常工作。

原始
目前,我无法访问Redshift集群进行测试,但是到家后就可以进行测试。以下方法的总体思路是,创建一个编号索引表进行交叉连接,以将权限字段中的数据扩展为基于行的表示形式。

我曾经询问过大小限制,因为当前只能处理10,000个可能的定界值,但是如果您的特定应用需要,您可以调整CTE以扩大到更大的数量:

修订版3查询:

        WITH

    pg_namespace AS (
        SELECT
            nspname
            , nspowner
            , rtrim(ltrim(array_to_string(nspacl, ','), '{'), '}') as nspacl
        FROM pg_catalog.pg_namespace
        WHERE nspname = 'public'
    ),

    -- Generating a table with the numbers 1 - 10 in a single column.
    ten_numbers AS (
        SELECT
            1 AS num
            UNION SELECT 2
            UNION SELECT 3
            UNION SELECT 4
            UNION SELECT 5
            UNION SELECT 6
            UNION SELECT 7
            UNION SELECT 8
            UNION SELECT 9
            UNION SELECT 0
    ),

    -- Expands the values in ten_numbers to create a single column with the values 1 - 10,000.
    depivot_index AS (
        SELECT
            (1000 * t1.num) + (100 * t2.num) + (10 * t3.num) + t4.num AS gen_num
        FROM ten_numbers AS t1
            JOIN ten_numbers AS t2 ON 1 = 1
            JOIN ten_numbers AS t3 ON 1 = 1
            JOIN ten_numbers AS t4 ON 1 = 1
    ),

    -- Filters down generated_numbers to house only the numbers up to the maximum times that the delimiter appears.
    splitter AS (
        SELECT
            *
        FROM depivot_index
        WHERE gen_num BETWEEN 1 AND (
            SELECT max(REGEXP_COUNT(nspacl, '\\,') + 1)
            FROM pg_namespace
            )
    ),

    -- Cross joins permissions_groups and splitter to populate all requests, delimited on ','.
    expanded_input AS (
        SELECT
            pg.nspname
            , pg.nspacl
            , trim(split_part(pg.nspacl, ',', s.gen_num)) AS raw_permissions_string
        FROM pg_namespace AS pg
            JOIN splitter AS s ON 1 = 1
        WHERE split_part(nspacl, ',', s.gen_num) <> ''
    ),

    -- Breaks out the owner and grantee fields into their own columns respectively.
    users_with_raw_permissions_data AS  (
        SELECT
            e.raw_permissions_string
            , e.nspname
            , trim(split_part(e.raw_permissions_string, '=', 1)) AS grantee
            , trim(split_part(trim(split_part(e.raw_permissions_string, '=', 2)), '/', 2)) AS owner
            , trim(split_part(trim(split_part(e.raw_permissions_string, '=', 2)), '/', 1)) AS raw_permissions_data

        FROM
        expanded_input e
    ),

    -- Mines privilege types from raw string data.
    access_privilege_types AS (
        SELECT
          u.nspname
          , u.owner
          , u.grantee
          ,CASE
            WHEN position('C*' IN u.raw_permissions_data) > 0 THEN 'C*'
            WHEN position('U*' IN u.raw_permissions_data) > 0 THEN 'U*'
            WHEN position('C' IN u.raw_permissions_data) > 0 THEN 'C'
            WHEN position('U' IN u.raw_permissions_data) > 0 THEN 'U'
            ELSE u.raw_permissions_data
          END AS first_access_privilege
          , CASE
            WHEN position('U*' IN u.raw_permissions_data) > 0 THEN 'U*'
            WHEN position('C*' IN u.raw_permissions_data) > 0 THEN 'C*'
            WHEN position('U' IN u.raw_permissions_data) > 0 THEN 'U'
            WHEN position('C' IN u.raw_permissions_data) > 0 THEN 'C'
             ELSE u.raw_permissions_data
          END AS second_access_privilege
        , first_access_privilege || ',' || second_access_privilege AS merged_access_privileges
        FROM users_with_raw_permissions_data u
    ),

    -- Cross joins access_privilge_types and splitter to populate all privilege_types, delimited on ','.
    expanded_access_privilege_types AS (
        SELECT
            a.nspname
            , a.owner
            , a.grantee
            , trim(split_part(a.merged_access_privileges, ',', s.gen_num)) AS access_privileges
        FROM access_privilege_types AS a
            JOIN splitter AS s ON 1 = 1
        WHERE split_part(a.merged_access_privileges, ',', s.gen_num) <> ''
        GROUP BY 1, 2, 3, 4
    )
SELECT
    ea.nspname
    , ea.owner
    , ea.grantee
    , LEFT(ea.access_privileges, 1) AS access_privilege
    , CASE
        WHEN POSITION('*' IN ea.access_privileges) > 0 THEN 'YES'
        ELSE 'NO'
      END AS is_grantable
FROM expanded_access_privilege_types ea
ORDER BY 1, 2, 3, 4, 5  

编辑#4:
添加一些关于ten_numbersdepivot_indexsplitter表如何分解pg_catalog.pg_namespace.nspacl字段的说明。总体概述是ten_numbersdepivot_index are created purely to return tables with numbered rows to use as an index when joining in the split_part values of nspacl`。

ten_numbers生成一个具有单个列的表,其中包含数字0-9:

-------
| num |
-------
|  0  |
-------
|  1  |
-------
| etc |
-------
|  9  |
------- 

然后在CTE depivot_index期间扩展此表以容纳范围0-9999:

-----------
| gen_num |
-----------
|    0    |
-----------
|    1    |
-----------
|    2    |
-----------
|   etc   |
-----------
|   9998  |
-----------
|   9999  |
----------- 

splitter然后缩小表格范围,只容纳nspacl字段中指定分隔符的最大数目以下的数字:

-------
| num |
-------
|  0  |
-------
|  1  |
-------
| etc |
-------
|  6  |
------- 

然后splitter返回的表通过CTE CROSS JOIN1 = 1上的联接用作expanded_input的目标。这样可以确保split_part返回的每个成员都有自己的行:

---------------------------------------------------------------------------
|  nspname  |               nspacl              |  raw_permissions_string |
---------------------------------------------------------------------------
|  avengers |  "{james=UC/james,adam=C/james}"  |      "james=UC/james"   |
---------------------------------------------------------------------------
|  avengers |  "{james=UC/james,adam=C/james}"  |       "adam=C/james"    |
---------------------------------------------------------------------------
|  avengers |                 etc.              |            etc.         |
---------------------------------------------------------------------------