将 aclitem 数组转换为多行 redshift
convert array of aclitem into multiple rows redshift
我有一个列值为
的数组
{詹姆斯=UC/james,亚当=C/james,克里斯=UC/詹姆斯,约翰=U/james}
以上列值不是json。它们是以下形式的字符串:
{ username=privilegestring/grantor }
如何将上面的列转换成多行
编辑#3:
更新了查询,通过 CTE pg_catalog 专门针对 pg_catalog.pg_namespace 授予 acl 权限。当前,此 CTE 在 where 子句中过滤为 select 单个命名空间名称 ('avengers'
);如果你想 select 来自多个命名空间名称,你应该能够将它们直接添加到此 CTE 的 WHERE
子句中,或者在需要所有命名空间名称的情况下,完全删除该子句。
同样值得注意的是,您需要扩展 access_privilege_types
中的 case 语句以处理所有权限案例:'r'、'w'、'a'、'd' 和 'x',用于操作:SELECT
、UPDATE
、INSERT
、DELETE
、REFERENCE
, 分别.
编辑#2:
下面查询的最终发布版本应该以您想要的格式为您提供所需的数据。我不知道权限类型有多少可能的值;如果当前指定的两个以上,则需要在 CTE* access_privilege_types
* 中扩展 case 语句。显然,您还需要在查询中替换您的 table 名称等。如果您 运行 遇到任何问题,请告诉我,我会在必要时提供帮助。
编辑#1:
能够验证此查询在 Redshift 中是否有效。更新了查询以按受让人和所有者拆分单独的行。当前版本还没有按行分解个人权限 -- 今晚晚些时候看看我是否也可以让它工作。
原文:
我目前无法访问我的 Redshift 集群来对此进行测试,但我会在回家后进行测试。以下方法背后的总体思路是创建一个编号索引 table 进行交叉连接,将权限字段中的数据扩展为基于行的表示形式。
我已经询问了大小限制,因为这目前只能处理 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_numbers
、depivot_index
和 splitter
table 如何拆分 pg_catalog.pg_namespace.nspacl
字段的说明。总体概述是 ten_numbers
和 depivot_index are created purely to return tables with numbered rows to use as an index when joining in the
split_partvalues of
nspacl`.
ten_numbers
生成具有单列的 table,包含数字 0-9:
-------
| num |
-------
| 0 |
-------
| 1 |
-------
| etc |
-------
| 9 |
-------
然后 table 在 CTE depivot_index
期间扩展到 0-9999 范围:
-----------
| gen_num |
-----------
| 0 |
-----------
| 1 |
-----------
| 2 |
-----------
| etc |
-----------
| 9998 |
-----------
| 9999 |
-----------
splitter
然后缩小 table 以仅容纳 nspacl
字段中指定分隔符的最大计数的数字:
-------
| num |
-------
| 0 |
-------
| 1 |
-------
| etc |
-------
| 6 |
-------
splitter
返回的 table 然后通过 CTE expanded_input
中 1 = 1
的连接用作 CROSS JOIN
的目标。这确保 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. |
---------------------------------------------------------------------------
我有一个列值为
的数组{詹姆斯=UC/james,亚当=C/james,克里斯=UC/詹姆斯,约翰=U/james}
以上列值不是json。它们是以下形式的字符串:
{ username=privilegestring/grantor }
如何将上面的列转换成多行
编辑#3:
更新了查询,通过 CTE pg_catalog 专门针对 pg_catalog.pg_namespace 授予 acl 权限。当前,此 CTE 在 where 子句中过滤为 select 单个命名空间名称 ('avengers'
);如果你想 select 来自多个命名空间名称,你应该能够将它们直接添加到此 CTE 的 WHERE
子句中,或者在需要所有命名空间名称的情况下,完全删除该子句。
同样值得注意的是,您需要扩展 access_privilege_types
中的 case 语句以处理所有权限案例:'r'、'w'、'a'、'd' 和 'x',用于操作:SELECT
、UPDATE
、INSERT
、DELETE
、REFERENCE
, 分别.
编辑#2:
下面查询的最终发布版本应该以您想要的格式为您提供所需的数据。我不知道权限类型有多少可能的值;如果当前指定的两个以上,则需要在 CTE* access_privilege_types
* 中扩展 case 语句。显然,您还需要在查询中替换您的 table 名称等。如果您 运行 遇到任何问题,请告诉我,我会在必要时提供帮助。
编辑#1:
能够验证此查询在 Redshift 中是否有效。更新了查询以按受让人和所有者拆分单独的行。当前版本还没有按行分解个人权限 -- 今晚晚些时候看看我是否也可以让它工作。
原文:
我目前无法访问我的 Redshift 集群来对此进行测试,但我会在回家后进行测试。以下方法背后的总体思路是创建一个编号索引 table 进行交叉连接,将权限字段中的数据扩展为基于行的表示形式。
我已经询问了大小限制,因为这目前只能处理 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_numbers
、depivot_index
和 splitter
table 如何拆分 pg_catalog.pg_namespace.nspacl
字段的说明。总体概述是 ten_numbers
和 depivot_index are created purely to return tables with numbered rows to use as an index when joining in the
split_partvalues of
nspacl`.
ten_numbers
生成具有单列的 table,包含数字 0-9:
------- | num | ------- | 0 | ------- | 1 | ------- | etc | ------- | 9 | -------
然后 table 在 CTE depivot_index
期间扩展到 0-9999 范围:
----------- | gen_num | ----------- | 0 | ----------- | 1 | ----------- | 2 | ----------- | etc | ----------- | 9998 | ----------- | 9999 | -----------
splitter
然后缩小 table 以仅容纳 nspacl
字段中指定分隔符的最大计数的数字:
------- | num | ------- | 0 | ------- | 1 | ------- | etc | ------- | 6 | -------
splitter
返回的 table 然后通过 CTE expanded_input
中 1 = 1
的连接用作 CROSS JOIN
的目标。这确保 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. | ---------------------------------------------------------------------------