J'ai les cinq tables suivantes, qui gèrent les relations entre utilisateurs, groupes et rôles dans une base de données:
Un utilisateur appartient à un groupe. Ces données sont stockées dans la table user_group, qui n'a que deux colonnes: user_fk et group_fk. Un groupe peut contenir de nombreux rôles. Cette info ist Saité dans la table GROUP_ROLE, qui n'a que deux colonnes: group_fk et role_fk. P>
Alors j'ai écrit la requête suivante sur ces 5 tables et le résultat de joint donne par exemple 5 rangées pour moi-même, car le Le groupe à qui j'appartiens contient 5 rôles. p>
SELECT user.last_name, user.first_name, user.user_name, group.name, role.name FROM user INNER JOIN user_group ON user_group.user_fk = user.id INNER JOIN group ON group.id = user_group.group_fk INNER JOIN group_role ON group.id = group_role.group_fk INNER JOIN role ON group_role.role_fk = role.id
4 Réponses :
Vous pouvez utiliser Listagg code> fonction d'agrégat avec Groupe par code> comme suit: SELECT user.last_name,
user.first_name,
user.user_name,
listagg(group.name,',') within group (order by group.name) as groupss,
listagg(role.name,',') within group (order by role.name) as roless
FROM user INNER JOIN user_group ON user_group.user_fk = user.id
INNER JOIN group ON group.id = user_group.group_fk
INNER JOIN group_role ON group.id = group_role.group_fk
INNER JOIN role ON group_role.role_fk = role.id
Group by user.last_name,
user.first_name,
user.user_name;
Essayez quelque chose comme ceci:
SELECT user.last_name, user.first_name, user.user_name, listagg(group.name || ' - ' ||role.name, ', ') within group (order by group.name, role.name) FROM user INNER JOIN user_group ON user_group.user_fk = user.id INNER JOIN group ON group.id = user_group.group_fk INNER JOIN group_role ON group.id = group_role.group_fk INNER JOIN role ON group_role.role_fk = role.id group by user.last_name, user.first_name, user.user_name
Je recommanderais deux sous-requêtes. Pourquoi? Les rôles peuvent être répétés et donc: p> vous pouviez Écrivez également ceci en utilisant une sous-requête et une agrégation conditionnelle: P> listagg () code> ne prend pas en charge distinct code>. select u.last_name, u.first_name, u.user_name,
listagg(case when seqnum_g = 1 then ugr.name end, ',') within group (order by ug.name) as groups,
listagg(case when seqnum_r = 1 then ugr.name end, ',') as roles within group (order by ur.name) as roles
from user u left join
(select ug.user_fk,
row_number() over (partition by ug.user_fk order by g.name) as seqnum_g,
row_number() over (partition by ug.user_rk order by r.name) as seqnum_r
from user_group ug join
group g join
on g.id = ug.group_fk join
group_role gr
on g.id = gr.group_fk join
role r
on gr.role_fk = r.id
) ugr
on ugr.user_fk = u.id
group by u.last_name, u.first_name, u.user_name;
Bonjour, le résultat est: "[42000]: ORA-00903: Nom de la table non valide". Il n'y a pas de table user_role et de champ user_role.user_fk.
@ user615993. . . Peut-être que je manque quelque chose mais je n'ai pas usé user_role code> dans ce code.
Je corrige ceci, c'était ma faute de frappe. Pourtant, 00904. 00000 - "% s: identifiant non valide" -error est renvoyé pour la rangée 3: 'ordre by r.name'. Il me semble que la table 'r' ne pouvait pas être atteinte à l'extérieur de la requête imbriquée
@ user615993. . . Je pense que j'ai réparé les alias.
Simplement agrégée par utilisateur et utilisez dans les versions antérieures que vous pouvez supprimer. Duplicates produits par listagg code> pour obtenir leurs groupes et leurs rôles. Vous avez besoin d'Oracle 19c pour cela, car Oracle a oublié de mettre en œuvre distinct code> pour listagg code> dans les versions antérieures. Listagg code> avec Regexp_replace CODE> à condition que la liste ne soit pas plus longue que listagg code> peut gérer. p> REGEXP_REPLACE(
LISTAGG(role.name, ', ') WITHIN GROUP (ORDER BY role.name),
'([^, ]+)(, \1)+($|, )',
'\1\3')
Fonctionne bien avec Regexp_replace
@ Thorsten Kettner, est-il un moyen de modifier la regex, de sorte que les entrées de données composées de plusieurs mots puissent être assorties? L'expression trouve et agrégats 'groupone', mais ne le fait pas pour "groupe deux"
En effet, le séparateur contient un blanc. La solution la plus simple consisterait à utiliser une seule virgule comme séparateur ( regexp_replace (listagg (rire.name, ',') au sein du groupe (commande par rôle.name), '([^,] +) (, \ 1 ) + ($ |,) ',' \ 1 \ 3 ') code>).
Cela fonctionne!, Même si je ne comprends pas cette expression de regex compliquée.
Les parenthèses fonctionnent comme des variables. Ce qui est à l'intérieur de la première paire de parenthèses (c'est [^,] + code> ici) est accessible par \ 1 code>, le contenu de la deuxième paire par \ \ 2 code>, etc. L'expression se lit comme suit: une série de caractères non-virgules ([^,] +) code> est suivi une ou plusieurs fois par une virgule et la même série (, \ 1) + code> et enfin suivi d'une autre virgule ou rien du tout, c'est-à-dire que c'est la fin de la chaîne ($ |,) code>. Chaque occurrence répétée d'une série de caractères est remplacée par une seule occurrence \ 1 code> suivie de la virgule de fuite ou de rien dans le cas de la fin de la chaîne \ 3 code>.
Savez-vous lequel des rôles voulez-vous montrer dans cette ligne?