-1

不要责怪数据库设计。我不是它的数据库架构师。我是在当前情况下必须使用它的人

我希望这是可以理解的。我有 3 个表,其中包含以下数据,它们没有外键关系:

groups
groupId    groupName
1          Admin 
2          Editor
3          Subscriber

preveleges
groupId    roles
1          1,2
2          2,3
3          1

roles
roleId    roleTitle
1         add
2         edit

询问:

SELECT roles 
from groups
LEFT JOIN preveleges ON (groups.groupId=preveleges.groupId)

返回特定的结果,即角色。

问题:我想在上述查询中显示roleTitle而不是角色。我很困惑如何将表角色与此查询相关联并返回所需的结果

我知道编码是可行的,但我想在 SQL 中使用。任何建议将不胜感激。

4

3 回答 3

3
SELECT g.groupName,
       GROUP_CONCAT(r.roleTitle 
                    ORDER BY FIND_IN_SET(r.roleId, p.roles))
         AS RoleTitles
FROM groups AS g
  LEFT JOIN preveleges AS p 
    ON g.groupId = p.groupId
  LEFT JOIN roles AS r
    ON FIND_IN_SET(r.roleId, p.roles)
GROUP BY g.groupName ;

测试于:SQL-FIDDLE

于 2013-05-10T11:11:14.897 回答
2

您还使用 PostgreSQL 标记了这个问题,使用 Postgres 解决这个损坏的设计实际上很容易:

SELECT grp.groupname, r.roletitle 
FROM groups grp
  join (
    select groupid, cast(regexp_split_to_table(roles, ',') as integer) as role_id
    from privileges
  ) as privs on privs.groupid = grp.groupid
  join roles r on r.roleid = privs.role_id;

SQLFiddle:http ://sqlfiddle.com/#!12/5e87b/1

(注意我把拼写错误的名字改成了preveleges正确的拼写privileges

但是你真的应该重新设计你的数据模型!

修复您的设计还使您能够定义外键约束并验证输入。'one,two,three'在您当前的模型中,如果有人将值插入到角色表中,应用程序可能会中断(就像我的查询一样) 。

编辑

为了完成图片,使用 Postgres 的数组处理上述可以使用类似于 MySQL 的方法稍微简化find_in_set()

select grp.groupname, r.roletitle 
from groups grp
  join privileges privs on grp.groupid = privs.groupid 
  join roles r on r.roleid::text = any (string_to_array(privs.roles, ','))

在这两种情况下,如果所有角色标题都应显示为逗号分隔列表,则可以使用 string_agg() 函数(相当于 MySQL 的group_concat()

select grp.groupname, string_agg(r.roletitle, ',')
from groups grp
  join privileges privs on grp.groupid = privs.groupid 
  join roles r on r.roleid::text = any (string_to_array(privs.roles, ','))
group by grp.groupname
于 2013-05-10T10:37:34.210 回答
2

我会改变它自己的数据结构。由于它没有标准化,因此单个列中有多个元素。

但是如果由于某种(有效的)原因您不能更改数据库,则使用 SQL 是可能的。

一个简单的“静态”解决方案:

SELECT REPLACE(REPLACE(roles, '1', 'add'), '2', 'edit') from groups
LEFT JOIN preveleges ON(groups.groupId=preveleges.groupId)

一个更复杂但仍然丑陋的解决方案:

CREATE FUNCTION ReplaceRoleIDWithName (@StringIds VARCHAR(50))
    RETURNS VARCHAR(50)
AS
BEGIN
    DECLARE @RoleNames VARCHAR(50)
    SET @RoleNames = @StringIds
    SELECT @RoleNames = REPLACE(@RoleNames, CAST(RoleId AS VARCHAR(50)), roleTitle)
    FROM roles
    RETURN @RoleNames
END

然后在查询中使用函数

SELECT ReplaceRoleIDWithName(roles) from groups
LEFT JOIN preveleges ON(groups.groupId=preveleges.groupId)

没有功能也可以,但这更具可读性。在没有编辑器的情况下制作,因此无论如何都没有经过测试。

于 2013-05-10T10:07:17.240 回答