【问题标题】:joining more than two tables without repeating values连接两个以上的表而不重复值
【发布时间】:2017-12-31 16:15:23
【问题描述】:

我想加入三个表,

我有三个表用户、职业和教育,其中“uid”是用户表的主键和其他两个表的外键。我想加入这些表以在一个表中产生结果

user              profession           education
+------+-------+  +-----+----------+  +-----+---------+
| uid  | uName |  | uid | profName |  | uid | eduName |
+------+-------+  +-----+----------+  +-----+---------+
|    1 | aaa   |  |   1 | prof1    |  |   1 | edu1    |
|    2 | bbb   |  |   1 | prof2    |  |   1 | edu2    |
|    3 | ccc   |  |   2 | prof1    |  |   1 | edu3    |
|      |       |  |   3 | prof3    |  |   3 | edu4    |
|      |       |  |   3 | prof2    |  |     |         |
+------+-------+  +-----+----------+  +-----+---------+


Expected output
+------+-------+-----+----------+-----+---------+
| uid  | uName | uid | profName | uid | eduName |
+------+-------+-----+----------+-----+---------+
|    1 | aaa   |   1 | prof1    |   1 | edu1    |
| null | null  |   1 | prof2    |   1 | edu2    |
| null | null  |null | null     |   1 | edu3    |
|    2 | bbb   |   2 | prof1    | null| null    |
|    3 | ccc   |   3 | prof3    |   3 | edu4    |
| null | null  |   3 | prof2    | null| null    |
+------+-------+-----+----------+-----+---------+

我尝试了以下查询

select u.uid ,u.uName,p.uid , p.profName,e.uid,e.eduName
from  user  u inner join profession p on u.uid=p.pid
inner join education e on u.uid = e.uid
where u.uid=p.uid
and u.uid=e.uid
and i.uid=1

这给了我重复的值

+------+-------+-----+----------+-----+---------+
| uid  | uName | uid | profName | uid | eduName |
+------+-------+-----+----------+-----+---------+
|    1 | aaa   |   1 | prof1    |   1 | edu1    |
|    1 | aaa   |   1 | prof2    |   1 | edu1    |
|    1 | aaa   |   1 | prof1    |   1 | edu2    |
|    1 | aaa   |   1 | prof2    |   1 | edu2    |
|    1 | aaa   |   1 | prof1    |   1 | edu3    |
|    1 | aaa   |   1 | prof2    |   1 | edu3    |
+------+-------+-----+----------+-----+---------+

有没有办法在不重复值的情况下获得输出。 谢谢

【问题讨论】:

  • 您想要重复值。 SQL 结果集没有固有的顺序。您想要的格式最好在应用层完成。
  • 查看你的结果,你没有重复的行..你有重复值的列..所以如果你需要不同的结果格式,你必须为演示文稿工作客户端
  • 您的空值逻辑不清楚。如果 prof1 和 prof2 的 uid 相同,那么为什么 prof1 有 aaa 而 prof2 有 null?这两行结果差异的逻辑是什么?
  • 由于您的表有重复的值,查询无法达到您的预期结果。请在您的代码上尝试。

标签: sql sql-server


【解决方案1】:

这个有点猪。

我同意@GordonLinoff 的观点,理想情况下,此演示将在客户端完成。

但是,如果我们希望在 SQL 中执行此操作,那么基本方法是您必须获取每个用户将使用的最大行数(基于他们在每个用户中有多少条目的计数)职业和教育表,然后是这些计数中的最大计数)。

一旦我们有了每个用户所需的行数,我们就会根据需要使用数字表为每个用户扩展行数(为此我已经包含了一个数字生成器)。

然后我们根据 uid 和连接表中条目的行号相对于每个用户的“扩展”行的行号来连接每个表。然后我们选择相关的列,我们就完成了。在出去的路上付钱给护士!

WITH 
number_table(number) AS
(
    SELECT
        (ones.n) + (10 * tens.n) + (100 * hundreds.n) AS number

    FROM --available range 0 to 999
         (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS ones(n)
        ,(VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS tens(n)
        ,(VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) AS hundreds(n)
)

,users(u_uid, userName) AS
(
    SELECT 1, 'aaa'
    UNION ALL
    SELECT 2, 'bbb'
    UNION ALL
    SELECT 3, 'ccc'
)

,professions(p_u_uid, profName) AS
(
    SELECT 1, 'prof1'
    UNION ALL
    SELECT 1, 'prof2'
    UNION ALL
    SELECT 2, 'prof1'
    UNION ALL
    SELECT 3, 'prof3'
    UNION ALL
    SELECT 3, 'prof2'
)
,educations(e_u_uid, eduName) AS
(
    SELECT 1, 'edu1'
    UNION ALL
    SELECT 1, 'edu2'
    UNION ALL
    SELECT 1, 'edu3'
    UNION ALL
    SELECT 3, 'edu4'
)

,row_counts(uid, row_count) AS
(
    SELECT u_uid, COUNT(u_uid) FROM users GROUP BY u_uid
    UNION ALL
    SELECT p_u_uid, COUNT(p_u_uid) FROM professions GROUP BY p_u_uid
    UNION ALL
    SELECT e_u_uid, COUNT(e_u_uid) FROM educations GROUP BY e_u_uid
)

,max_counts(uid, max_count) AS
(
    SELECT uid, MAX(row_count) FROM row_counts GROUP BY uid
)

SELECT 
    u_uid
    ,userName
    ,p_u_uid
    ,profName
    ,e_u_uid
    ,eduName

FROM
    max_counts 

INNER JOIN 
    number_table ON number BETWEEN 1 AND max_count

LEFT JOIN 
    (
        SELECT u_uid, userName, ROW_NUMBER() OVER (PARTITION BY u_uid ORDER BY userName) AS user_match
        FROM users
    ) AS users
    ON u_uid = uid
    AND number = user_match

LEFT JOIN 
    (
        SELECT p_u_uid, profName, ROW_NUMBER() OVER (PARTITION BY p_u_uid ORDER BY profName) AS prof_match
        FROM professions
    ) AS professions
    ON p_u_uid = uid
    AND number = prof_match

LEFT JOIN 
    (
        SELECT e_u_uid, eduName, ROW_NUMBER() OVER (PARTITION BY e_u_uid ORDER BY eduName) AS edu_match
        FROM educations
    ) AS educations
    ON e_u_uid = uid
    AND number = edu_match

ORDER BY 
     IIF(COALESCE(u_uid, p_u_uid, e_u_uid) IS NULL, 1, 0)   ASC --nulls last
    ,COALESCE(u_uid, p_u_uid, e_u_uid)                      ASC
    ,IIF(COALESCE(p_u_uid, e_u_uid) IS NULL, 1, 0)          ASC --nulls last
    ,COALESCE(p_u_uid, e_u_uid)                             ASC
    ,IIF(e_u_uid IS NULL, 1, 0)                             ASC --nulls last
    ,e_u_uid                                                ASC

结果:

u_uid       userName p_u_uid     profName e_u_uid     eduName
----------- -------- ----------- -------- ----------- -------
1           aaa      1           prof1    1           edu1
NULL        NULL     1           prof2    1           edu2
NULL        NULL     NULL        NULL     1           edu3
2           bbb      2           prof1    NULL        NULL
3           ccc      3           prof2    3           edu4
NULL        NULL     3           prof3    NULL        NULL

【讨论】:

    【解决方案2】:

    您尝试过distinct 关键字吗?

    select DISTINCT u.uid ,u.uName,p.uid , p.profName,e.uid,e.eduName
    from  user  u inner join profession p on u.uid=p.pid
    inner join education e on u.uid = e.uid
    where u.uid=p.uid
    and u.uid=e.uid
    and i.uid=1
    

    【讨论】:

    • 那么,它不是在做你需要的吗?
    猜你喜欢
    • 1970-01-01
    • 2016-11-24
    • 2021-09-08
    • 1970-01-01
    • 1970-01-01
    • 2015-12-06
    • 1970-01-01
    • 2014-12-27
    • 2021-12-26
    相关资源
    最近更新 更多