SQL:利用标准表,将不同类型的标准应用于不同的字段

Posted

技术标签:

【中文标题】SQL:利用标准表,将不同类型的标准应用于不同的字段【英文标题】:SQL: Utilizing criteria table with different types of criteria applied to different fields 【发布时间】:2021-12-30 15:32:58 【问题描述】:

我正在研究如何向具有标准表的用户提供权限,该标准表具有与我的数据集中不同字段匹配的字段/值对。

下面是权限表。

Field Value Permissioned user
region AMER Kim
manager Chris Kim
division Sales Kim
region EMEA Julie
manager Jim Julie

这是数据的格式。不同的字段代表上面的不同字段。可能有 8 个或更多不同的字段(例如区域、业务部门、部门主管等),因此我需要一种可以扩展超出我的虚拟数据集的方法。

EMP ID region division manager
1 AMER Marketing Chris
2 AMER Sales Chris
3 EMEA Sales Chris
4 AMER Sales Jim
5 EMEA Marketing Jim
6 EMEA Sales Jim

所需的输出将标准应用于不同的字段。

Permisioned User EMP ID region division manager
Kim 2 AMER Sales Chris
Julie 5 EMEA Marketing Jim
Julie 6 EMEA Sales Jim

我不确定从哪里开始,因为我似乎无法靠近。相交意味着我总是在标准中应用相同的字段,但事实并非如此。另外,不同的用户可以有不同数量的标准规则。非常感谢任何帮助!

谢谢!

【问题讨论】:

【参考方案1】:

如果可用于定义权限的详尽字段列表已修复,则您可以创建静态查询。如果字段列表不是固定的并且仅在运行时才知道,那么您需要动态查询。

权限字段静态列表/静态查询

我们交叉加入permissionsdata 表。 然后,我们按"Permissioned user""EMP ID" 对行进行分组,并且由于HAVING 子句中的聚合函数bool_and,我们只保留所有满足(字段,值)对应的分组行。 最后我们添加数据表的所有列,并按“EMP ID”排序:

WITH list AS
(
SELECT p."Permissioned user"
     , d."EMP ID"
  FROM data AS d
 CROSS JOIN permissions AS p
 GROUP BY p."Permissioned user", d."EMP ID"
HAVING bool_and( CASE 
                   WHEN p.field = 'region' THEN p.value = d.region
                   WHEN p.field = 'manager' THEN p.value = d.manager
                   WHEN p.field = 'division' THEN p.value = d.division
                   WHEN [...]  -- insert here the rest of the fields list
                   ELSE FALSE
                 END
               )
)
SELECT l."Permissioned user", d.*
  FROM list AS l
 INNER JOIN data AS d
    ON d."EMP ID" = l."EMP ID"
 ORDER BY d."EMP ID" ;

权限字段变量列表/动态查询

动态查询允许根据仅在运行时已知的条件搜索数据。它必须嵌入到将返回动态查询结果的 plpgsql 函数中。对于表permissions 中的每个“Permissioned user”,其原理是生成与表data 中查询搜索的WHERE 子句匹配的where_clause 字符串。 "Permissioned user"where_clause 被传递给 plpgsql 函数permissioned_user,其中包含动态查询并返回 "EMP ID" 列表 em> 在表中data

CREATE OR REPLACE FUNCTION permissioned_user 
( INOUT "Permissioned user" text
, IN where_clause text
, OUT "EMP ID" integer
)
RETURNS setof record LANGUAGE plpgsql IMMUTABLE AS
$$
BEGIN  
RETURN QUERY EXECUTE E'
    SELECT ' || quote_nullable("Permissioned user") || E'
         , "EMP ID"
      FROM data AS d
     WHERE ' || where_clause ;
END ;
$$

然后下面的查询返回预期的结果。首先,它生成与表permissions 中的每个“许可用户”相关联的 where_clause 字符串。然后它调用function permissioned_user(),获取"EMP ID" 列表并加入data 的其余列:

WITH list AS
(   SELECT "Permissioned user"
         , string_agg('d.' || quote_ident(Field) || E' = \'' || quote_nullable(Value) || E'\'', ' AND ') AS where_clause
      FROM permissions
     GROUP BY "Permissioned user"
)
SELECT a."Permissioned user", d.*
  FROM list AS l
 CROSS JOIN LATERAL permissioned_user(l."Permissioned user", l.where_clause) AS a
 INNER JOIN data AS d
    ON d."EMP ID" = a."EMP ID"
  ORDER BY a."EMP ID"

请注意,表permissions 中的任何字段 值与data 表中的列名不对应都会产生SQL 错误。

【讨论】:

很好的解释!作为一个中等级别的 SQL 用户,我现在被卡住的感觉并不那么糟糕 :)

以上是关于SQL:利用标准表,将不同类型的标准应用于不同的字段的主要内容,如果未能解决你的问题,请参考以下文章

数据库和SQL应用三(译)

串联型PID,并联型PID与标准型PID简要说明

旧版 sql 和标准 sql 之间的 BigQuery 表分区差异

如何写出能适应不同数据库的SQL查询

标准sql执行顺序

SQL Server Web 与标准版