【问题标题】:SQL join between table rows表行之间的 SQL 连接
【发布时间】:2017-12-15 10:37:13
【问题描述】:

我有一个关于 sql 查询的问题,对我来说这似乎很简单,但无法让它正常工作。

所以我有这张桌子:

broadcast_media_id 告诉我数据是 1 - 电子邮件还是 2 - 电话。我需要为一名员工(具有相同的employee_id)收集电子邮件和电话。

我试过的查询是这样的:

SELECT DISTINCT ed.employee_id,
    ed.text_value AS email,
    x.text_value AS phone
FROM employee_data ed
    INNER JOIN
        (
            SELECT employee_id,
                text_value
            FROM employee_data
            WHERE broadcast_media_id = 2
        ) x ON x.employee_id = ed.employee_id
WHERE broadcast_media_id = 1

不幸的是,由于 WHERE 子句,我只有在员工有电子邮件时才能获得值。所以结果是这样的:

我错过了“A773B230-754C-423F-97C4-E331268EA3C8”的电话号码,因为他没有电子邮件。我也想显示这一行,并且电子邮件的值为 NULL。

对我来说似乎很简单,但我无法弄清楚。

感谢您的帮助。

【问题讨论】:

  • 然后使用left join

标签: sql sql-server outer-join


【解决方案1】:

如果你想使用join,你可以使用LEFT JOIN

SELECT ed.employee_id, ede.text_value AS email,
       edp.text_value AS phone
FROM employees e LEFT JOIN
     employee_data ede
     ON ede.employee_id = e.employee_id AND
        ede.broadcast_media_id = 1 LEFT JOIN
     employee_data edp
     ON edp.employee_id = e.employee_id AND
        edp.broadcast_media_id = 2

注意:这假设您有一个employees 表——这似乎很合理。这对于LEFT JOIN 来说非常方便。这可能会有最好的性能。

如果您没有employees 表,则使用子查询(SELECT DISTINCT employee_id FROM employee_data)

我倾向于使用条件聚合来做到这一点,它也应该具有合理的性能。

【讨论】:

  • 我有员工表,是的,但我不想参与其中。这似乎有效:SELECT DISTINCT ed.employee_id, ede.text_value AS email, edp.text_value AS phone FROM employee_data ed LEFT JOIN employee_data ede ON ede.employee_id = ed.employee_id AND ede.broadcast_media_id = 1 LEFT JOIN employee_data edp ON edp。 employee_id = ed.employee_id AND edp.broadcast_media_id = 2 谢谢
  • @IvanBinev 。 . .如果您关心性能,那么员工表的效率会更高。
  • 嗯,我可以,但左加入不行,因为员工可能没有电话和电子邮件,我不想向没有它们的员工展示。
【解决方案2】:

试试这个查询——虽然我没有使用任何连接

Select
    EmpID,
    Max(Case When MediaID = 1 Then TextValue End) As EmailID,
    Sum(Case When MediaID = 2 Then Cast(TextValue As Int) End) As PhoneNumber
From employee_data
Group By EmpID
Order By EmpID;

这里 - 排序成本 = 78% 和表扫描 = 22%。 (我的实例数据,肯定会随着你的系统和数据而变化。)

如果你做一些索引,那么它会表现得更好。

【讨论】:

    【解决方案3】:

    如果员工总是有电话,只需使用 LEFT JOIN。

    SELECT DISTINCT ed.employee_id,
        ed.text_value AS email,
        x.text_value AS phone
    FROM employee_data ed
        LEFT JOIN
            (
                SELECT employee_id,
                    text_value
                FROM employee_data
                WHERE broadcast_media_id = 2
            ) x ON x.employee_id = ed.employee_id
    WHERE broadcast_media_id = 1
    

    你也可以避免自加入,但很可能性能会更差

    SELECT ed.employee_id,
            MIN(CASE WHEN broadcast_media_id = 1 THEN text_value END) AS phone,
            MIN(CASE WHEN broadcast_media_id = 2 THEN text_value END) AS email
    FROM employee_data ed
    GROUP BY ed.employee_id
    

    如果员工可以没有电话,那么你可以使用 FULL JOIN

    SELECT DISTINCT
        COALESCE(ed.employee_id, x.employee_id) employee_id,
        ed.text_value AS email,
        x.text_value AS phone
    FROM
        (SELECT * FROM employee_data WHERE broadcast_media_id = 1) ed
        FULL JOIN (SELECT * FROM employee_data WHERE broadcast_media_id = 2) x
            ON x.employee_id = ed.employee_id;
    

    【讨论】:

    • 员工可以没有电话或/和没有电子邮件。我尝试了FULL JOIN,但它只给了我两行相同的结果(因为'WHERE broadcast_media_id = 1'从其他连接中删除了行)。您建议的第二个查询工作正常。为什么说性能会更差?
    • 感谢您的回答,MIN 答案有效,但我接受了另一个没有聚合函数的答案。这是一个非常好的替代方案,绝对有用!
    • 添加了 FULL JOIN 示例
    【解决方案4】:

    我会使用双 LEFT JOIN,例如:

        SELECT ed.employee_id
              ,COALESCE(ed1.text_value,'') as mail
              ,COALESCE(ed2.text_value,'') as phone
          FROM employee_data ed
     LEFT JOIN employee_data ed1
            ON ed.employee_id = ed1.employee_id
           AND ed1.broadcast_media_id = 1
     LEFT JOIN employee_data ed2
            ON ed.employee_id = ed2.employee_id
           AND ed2.broadcast_media_id = 2   
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-22
      • 1970-01-01
      • 2012-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多