You can do this by taking advantage of the fact the listagg()
ignores NULL
values. So, use row_number()
to enumerate duplicates and then just pull in the first value:
SELECT grantee,
LISTAGG(CASE WHEN seqnum_granted_role = 1 THEN granted_role END, '-')
WITHIN GROUP (ORDER BY granted_role) AS granted_role,
LISTAGG(CASE WHEN seqnum_privilege = 1 THEN privilege END, '-')
WITHIN GROUP (ORDER BY privilege) AS privs,
owner,
table_name
FROM (SELECT grantee, granted_role, privilege,
owner, table_name,
ROW_NUMBER() OVER (PARTITION BY grantee, owner, table_name, granted_role
ORDER BY grantee
) as seqnum_granted_role,
ROW_NUMBER() OVER (PARTITION BY grantee, owner, table_name, privilege
ORDER BY grantee
) as seqnum_privilege
FROM sys.privs
) p
GROUP BY grantee, owner, table_name;