2

我们正在构建一个数据库,该数据库将用于检查公司各个系统上员工当前使用的用户名的任何重复项。以前,一些员工共享相同的用户名访问某些系统。由于方向是为每个系统上的每个员工都有一个唯一的用户名,因此我们需要确定哪些员工仍在使用共享访问权限。该数据库有一张表,其中包含员工的姓名及其各自的用户名。

例如:表1

Employee    System1 System2  System3
John Doe    dJohn   Pkls453  xfd801
Jane Doe    dJane   Pkls454  xfd801
James Lee   dJames  Pkls455  fd674
Mark Jones  dMark   Pkls453  xfd752

我们需要生成一个报告,表明 John Doe 和 Jane Doe 在 System3 上共享相同的访问权限,而 John Doe 和 Mark Jones 在 System2 上共享访问权限。就像是:

Employee  System3  System2
John Doe  xfd801
Jane Doe  xfd801
John Doe           Pkls453
Mark Jones         Pkls453

有没有办法解决这个问题?

提前致谢...

4

2 回答 2

2

我确信有一个更清洁的解决方案,但这应该以您指定的格式返回您正在寻找的内容。

SELECT Employee, System1, NULL AS System2, NULL AS System3
FROM your_table T1
WHERE EXISTS(SELECT * FROM your_table T2
         WHERE T1.System1 = T2.System1
         AND T1.Employee <> T2.Employee)
UNION
SELECT Employee, NULL AS System1, System2, NULL AS System3
FROM your_table T1
WHERE EXISTS(SELECT * FROM your_table T2
         WHERE T1.System2 = T2.System2
         AND T1.Employee <> T2.Employee)
UNION
SELECT Employee, NULL AS System1, NULL AS System2, System3
FROM your_table T1
WHERE EXISTS(SELECT * FROM your_table T2
         WHERE T1.System3 = T2.System3
         AND T1.Employee <> T2.Employee)
ORDER BY System1, System2, System3
于 2012-08-14T22:10:44.550 回答
2

如果您的系统支持窗口函数,这将起作用:

SELECT employee, system1, system2, system3
FROM  (
   SELECT employee
         ,system1
         ,cast(NULL AS text) AS system2
         ,cast(NULL AS text) AS system3
         ,count(*) OVER (PARTITION BY system1) AS ct
   FROM tbl1

   UNION  ALL
   SELECT employee
         ,NULL -- cast and column name only needed in first SELECT in Postgres
         ,system2
         ,NULL
         ,count(*) OVER (PARTITION BY system2) AS ct
   FROM   tbl1

   UNION  ALL
   SELECT employee
         ,NULL
         ,NULL
         ,system3
         ,count(*) OVER (PARTITION BY system3) AS ct
   FROM   tbl1
   ) x
WHERE  ct > 1
ORDER  BY system1, system2, system3;

或者,可能更快:
请注意,共享多个系统的“John Doe”在其所有共享系统的以下查询中仅列出一次(而不是第一个)。非共享系统设置为NULL

SELECT employee
      ,CASE WHEN ct1 > 1 THEN system1 ELSE NULL END AS system1
      ,CASE WHEN ct2 > 1 THEN system2 ELSE NULL END AS system2
      ,CASE WHEN ct3 > 1 THEN system3 ELSE NULL END AS system3
FROM   (
    SELECT employee, system1, system2, system3
          ,count(*) OVER (PARTITION BY system1) AS ct1
          ,count(*) OVER (PARTITION BY system2) AS ct2
          ,count(*) OVER (PARTITION BY system3) AS ct3
    FROM tbl1
    ) x
WHERE  ct1 > 1 OR ct2 > 1 OR ct3 > 1
ORDER  BY system1, system2, system3; -- depends on what you want

或者,如果您的匿名系统支持公用表表达式:

WITH x AS (
    SELECT employee, system1, system2, system3
          ,count(*) OVER (PARTITION BY system1) AS ct1
          ,count(*) OVER (PARTITION BY system2) AS ct2
          ,count(*) OVER (PARTITION BY system3) AS ct3
    FROM tbl1
    )
SELECT employee
      ,CASE WHEN ct1 > 1 THEN system1 ELSE NULL END AS system1
      ,CASE WHEN ct2 > 1 THEN system2 ELSE NULL END AS system2
      ,CASE WHEN ct3 > 1 THEN system3 ELSE NULL END AS system3
FROM   x
WHERE  ct1 > 1 OR ct2 > 1 OR ct3 > 1
ORDER  BY system1, system2, system3; -- depends

如果您既没有 CTE 也没有窗口函数:(
应该适用于所有主要的 RDBMS,包括 MySQL。)

SELECT t.employee, s1.system1, s2.system2, s3.system3
FROM   tbl1 t
LEFT   JOIN (SELECT system1 FROM tbl1 GROUP BY 1 HAVING count(*) > 1) s1
                                                 ON t.system1 = s1.system1
LEFT   JOIN (SELECT system2 FROM tbl1 GROUP BY 1 HAVING count(*) > 1) s2
                                                 ON t.system2 = s2.system2
LEFT   JOIN (SELECT system3 FROM tbl1 GROUP BY 1 HAVING count(*) > 1) s3
                                                 ON t.system3 = s3.system3
WHERE s1.system1 IS NOT NULL
   OR s2.system2 IS NOT NULL
   OR s3.system3 IS NOT NULL
ORDER BY s1.system1, s2.system2, s3.system3; -- depends

用 PostgreSQL 9.1.4 测试。

于 2012-08-14T22:14:31.023 回答