我有三张table:用户、权限和用户权限,Map前两个表中的值。示例:
表“用户”
| 识别号|登录|
| - ------|- ------|
| 1个|测试1|
| 第二章|测试2|
表“权限”
| 识别号|姓名|
| - ------|- ------|
| 1个|读出|
| 第二章|写|
| 三个|写|
表“用户权限”
| 用户ID|右侧ID|
| - ------|- ------|
| 1个|1个|
| 1个|第二章|
| 1个|三个|
| 第二章|第二章|
我有一个查询来检查用户是否具有适当的权限。查询的输出如下所示:
| 登录|权利|
| - ------|- ------|
| 测试1|读取=真;写入=真|
| 测试2|return false;write=true|
问题是在表'Rights'中可能存在一些与其他关系重复的内容。因此脚本输出可能如下所示:
| 登录|权利|
| - ------|- ------|
| 测试1|return true; return true;write=true|
| 测试2|return false;write=true;write=false|
我想只选择不同的权利,如果至少有一个副本具有“true”,我想为每个这样的权利选择“true”值。
我使用这个查询来获得预期的结果,但它没有考虑是否有任何重复的右边值为“true”:
SELECT u.login,
LISTAGG(DISTINCT r.name || '=' ||
CASE
WHEN ur.user_id IS NOT NULL THEN
'true'
ELSE
'false'
END,
'; ')
WITHIN GROUP ( ORDER BY r.name ) AS rights
FROM users u
CROSS JOIN rights r
LEFT JOIN userrights ur
ON ur.user_id = u.id
AND ur.right_id = r.id
GROUP BY u.login;
另外,我想摆脱打印r.name,但我使用它来过滤出唯一的值。
我们现在正在从这个模式迁移,因此纠正DB一致性比纠正脚本更困难。
2条答案
按热度按时间krugob8w1#
通过向表中添加主键/唯一约束来修复数据(而不是查询):
那么在一个表中就不可能有重复的权限。
也不可能(具有或不具有约束)具有同时是
true
和false
的权限,因为true
由UserRights
表中匹配行的存在给出,而false
由非匹配行的存在给出。在UserRights
表中存在匹配行,并且对于相同的用户和权限组合,在UserRights
表中既存在行又不存在行的情况是不可能的。UserRights
表;这些行为是相互排斥的。如果在应用约束之前有重复项,则可以使用以下命令将其删除:
删除重复项并应用约束后,您可以使用查询(或聚合主键):
对于您的示例数据,输出:
| 登录|权利|
| - ------|- ------|
| 测试1|读取=真;写入=假|
| 测试2|读取=真;写入=真|
fiddle
如果在
UserRights
表中有重复的数据,那么应该修复数据并添加约束;如果您不打算这样做(您应该这样做),则可以使用DISTINCT
:或:
fiddle
更新:重名权限
如果您有重复名称的权限,请修复数据。
例如,给定数据:
然后,您可以使用以下命令合并重复项:
并删除(现在未使用的)重复权限:
然后,您可以添加一个约束来防止这种情况再次发生:
然后:
输出:
| 登录|权利|
| - ------|- ------|
| 测试1|读取=真;写入=假|
| 测试2|读取=真;写入=真|
| 测试3|return false;write=true|
| 测试4|return false;write=true|
fiddle
hec6srdp2#
这样做的一个选项可能是这样的:
子查询检查任何特定用户是否具有读、写或两者都有权限,并将其放置在用户的第一行。主查询只是连接值,如果它们存在或不存在,则给出true或false。
使用示例数据:
...那就是
另外,如果你有一个用户不在users_rights表中,假设用户ID=3 LOGIN=test3,那么这将返回另一行,如下所示: