繁体   English   中英

将同一列上的同一表(多次)连接到不同的表

[英]Join the same table (multiple times) on same column to different tables

我到处都看过,但我无法找到一种有效的方式将一个表连接到同一列上的多个表。 比方说,我有如下表格:

员工

emp_id | emp_name | gender_id | age_range_id
----------------------------------------------
101    | adam     | 1         | 3
102    | ashley   | 2         | 2
103    | Cody     | 1         | 4

游客

visitor_id | visitor_name | gender_id | emp_id | age_range_id
---------------------------------------------------------------
501        | john         | 1         | 101    | 3
502        | lily         | 2         | 101    | null
503        | jeff         | 1         | 102    | 2

性别

gender_id | gender_name
--------------------------
1         | male
2         | female       

年龄范围

age_range_id | age_range_name
------------------------------
1            | 18-25
2            | 26-35     
3            | 36-45
4            | 46-55
5            | 56-65

我想要的是:

emp_id | emp_name | emp_gender_and_age_range | visitor_name | visitor_gender_and_age_range
---------------------------------------------------------------------------------------------------
101    | adam     | male 36-45               | john         | male 36-45
101    | adam     | male 36-45               | lily         | female       
102    | ashley   | female 26-35             | jeff         | male 26-35       
103    | Cody     | male 46-55               | null         | null

我的代码:

SELECT e.emp_id
      ,e.emp_name
      ,g1.gender_name || ' ' || a1.age_range_name emp_gender_and_age_range
      ,v.visitor_name
      ,g2.gender_name || ' ' || a2.age_range_name emp_gender_and_age_range
  FROM employee e
       LEFT JOIN gender g1 ON e.gender_id = g1.gender_id
       LEFT JOIN age_range a1 ON e.age_range_id = a1.age_range_id
       LEFT JOIN visitor v ON e.emp_id = v.emp_id
       LEFT JOIN gender g2 ON v.gender_id = g2.gender_id
       LEFT JOIN age_range a2 ON v.age_range_id = a2.age_range_id

有没有一种有效的方法可以在不加入两次的情况下在员工访客身上显示性别姓名

我还在Select部分尝试了子查询:

SELECT e.emp_id
      ,e.emp_name
      ,(SELECT g1.gender_name || ' ' || a1.age_range_name
          FROM gender g1, age_range a1
         WHERE e.gender_id = g1.gender_id AND e.age_range_id = a1.age_range_id)
           emp_gender_and_age_range
      ,g1.gender_name || ' ' || a1.age_range_name
           emp_gender_and_age_range
      ,v.visitor_name
      ,(SELECT g2.gender_name || ' ' || a2.age_range_name
          FROM gender g2, age_range a2
         WHERE v.gender_id = g2.gender_id AND v.age_range_id = a2.age_range_id)
           visitor_gender_and_age_range
  FROM employee e
       -- LEFT JOIN gender g1 ON e.gender_id = g1.gender_id
       -- LEFT JOIN age_range a1 ON e.age_range_id = a1.age_range_id
       LEFT JOIN visitor v ON e.emp_id = v.emp_id
       -- LEFT JOIN gender g2 ON v.gender_id = g2.gender_id
       -- LEFT JOIN age_range a2 ON v.age_range_id = a2.age_range_id

但是,上述查询的问题是, visitor_gender_and_age_rangeLily返回null

emp_id | emp_name | emp_gender_and_age_range | visitor_name | visitor_gender_and_age_range
---------------------------------------------------------------------------------------------------
101    | adam     | male 36-45               | john         | male 36-45
101    | adam     | male 36-45               | lily         | **NULL**      
102    | ashley   | female 26-35             | jeff         | male 26-35       
103    | Cody     | male 46-55               | null         | null

注意:我没有特别测试上面的查询。 但是,我的表与上面的示例完全相似。

谢谢你。

否。在这两种情况下(员工和访客),性别和年龄范围都是查找代码。 这些代码中的每一个都必须分别在 gender 和 age_range 表中查找。

每个查找都需要自己的连接,因为每个查找都可能返回不同的行。

不,你不能,但你可以使用SQL 标量宏来使其更短/更容易阅读,以防 Oracle 21+。

SQL 标量宏示例: DBFiddle 上的完整示例

create or replace function get_gender_age(p_gender_id int, p_age_range_id int)
  return varchar2 sql_macro(scalar)
is
begin
  return q'[(
    (SELECT gender_name from gender where gender_id = p_gender_id)
    ||' '||
    (SELECT age_range_name from age_range where age_range_id = p_age_range_id)
  )]';
end;
/

并查询:

SELECT e.emp_id
      ,e.emp_name
      ,get_gender_age(e.gender_id,e.age_range_id) as emp_gender_and_age_range
      ,v.visitor_name
      ,get_gender_age(v.gender_id,v.age_range_id) as vis_gender_and_age_range
FROM employee e
     LEFT JOIN visitor v ON e.emp_id = v.emp_id

(您也可以使用内联 PL/SQL 函数,但我不建议这样做,因为在这种情况下性能较低)

或者您可以使用 CTE:

with gender_age as (
    SELECT 
         g.gender_id
        ,a.age_range_id
        ,g.gender_name || ' ' || a1.age_range_name as gender_and_age_range
    FROM gender g, age_range a
)
SELECT e.emp_id
      ,e.emp_name
      ,g1.gender_and_age_range as emp_gender_and_age_range
      ,v.visitor_name
      ,g2.gender_and_age_range as vis_gender_and_age_range
FROM 
    employee e
    LEFT JOIN gender_age g1 USING(gender_id, age_range_id)
    LEFT JOIN visitor v ON e.emp_id = v.emp_id
    LEFT JOIN gender_age g2 USING(gender_id, age_range_id)

但是不管怎么说,还是2次查找。

有没有一种有效的方法可以在不加入两次的情况下在员工和访客身上显示性别姓名?

根据关系代数,连接两次是连接这些关系的标准方法。

此外,您还需要考虑,如果索引gender (gender_id)可用,加入两次会非常有效。 我不会花时间解决这两个连接问题。

我看不到你对此的担忧。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM