-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

私はデータ構造自体を変更します。正規化されていないため、1 つの列に複数の要素があります。

ただし、何らかの(有効な)理由でDBを変更できない場合は、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 に答える