MySql:使用嵌套关系表获取用户详细信息

时间:2016-05-28 13:09:07

标签: php mysql sql relational-database

在表usersstu_masterstu_infoemp_masteremp_info下方显示。

用户

enter image description here

stu_master

stu_master_user_id = users.user_id

enter image description here

stu_info

stu_info_id = stu_master.stu_master_stu_info_id

![enter image description here

emp_master

em_user_id = users.user_id

enter image description here

emp_info

emp_info_id = emp_master.em_emp_info_id

![enter image description here

我使用以上5个表进行单个查询获得用户名或姓;

我有两种类型的用户,一种是Student,另一种是Employee,其登录详细信息存储在单个表中,其名称为Users。但是我根据用户类型在两个不同的表中存储名/姓相关的详细信息存储。如果用户类型为 S 。我将使用stu_info表在stu_master中获得名/姓,因为user_id关系在stu_master表中可用,其他明智的用户类型是E,在{中获取名/姓{1}}使用emp_info表因为emp_master表中的emp_master关系。

我的表关系:

  • 对于Student = Users-> stu_master-> stu_info,
  • For Employee = Users-> emp_master-> emp_info,

我已尝试以下查询,但未获得预期结果。

user_id

上述查询返回SELECT user_id as UserId, stu_first_name as FirstName, stu_last_name as LastName, user_type as UserType FROM `users` LEFT JOIN stu_master tsm ON (stu_master_user_id = user_id AND `user_type` = 'S') LEFT JOIN stu_info tsi ON (tsm.stu_master_stu_info_id = tsi.stu_info_id) UNION ALL SELECT user_id as UserId, emp_first_name as FirstName, emp_last_name as LastName, user_type as UserType FROM `users` LEFT JOIN emp_master tem ON (em_user_id = user_id AND `user_type` = 'E') LEFT JOIN emp_info tei ON (tem.em_id = tei.emp_info_id) WHERE `user_id` IN (1, 2, 3, 4, 5, 6); all student。 显示输出

![enter image description here

我只使用任何一个查询获得名字(1,2,3,4,5,6)的名/姓。

请给我任何类型的单一查询以达到我的要求或修改我的上述查询。

3 个答案:

答案 0 :(得分:3)

如果您想要所有学生和当前架构中的所有雇主,那么您可以直接离开:

   SELECT tu.user_id as UserId,
          tsi.stu_first_name as FirstName,
          tsi.stu_last_name as LastName,
          tu.user_type as UserType 
     FROM users tu 
LEFT JOIN stu_master tsm 
       ON tsm.stu_master_user_id = tu.user_id 
LEFT JOIN stu_info tsi 
       ON tsi.stu_info_id = tsm.stu_master_stu_info_id
    WHERE tu.user_type = 'S'

    UNION ALL

   SELECT tu.user_id as UserId,
          tei.emp_first_name as FirstName,
          tei.emp_last_name as LastName,
          tu.user_type as UserType 
     FROM users tu 
LEFT JOIN emp_master tem 
       ON tem.em_user_id = tu.user_id 
LEFT JOIN emp_info tei 
       ON tei.emp_info_id = tsm.em_emp_info_id
    WHERE tu.user_type = 'E'

在您的查询中,您将user_type条件放在LEFT JOIN中,因此仍会返回另一种类型的记录(使用NULLed名称)。您的WHERE也仅适用于第二个SELECT。

如果你想在两个SELECTS上添加一个条件,你需要将它复制为两个WHERE,或者将两个UNIONed语句用一个WHERE包装在外部SELECT中。

其他选项

假设员工或学生没有丢失/重复的信息记录,您实际上可以将这些LEFT JOIN更改为直接JOIN并删除WHERE:

SELECT tu.user_id as UserId,
       tsi.stu_first_name as FirstName,
       tsi.stu_last_name as LastName,
       tu.user_type as UserType 
  FROM users tu 
  JOIN stu_master tsm 
    ON tsm.stu_master_user_id = tu.user_id 
  JOIN stu_info tsi 
    ON tsi.stu_info_id = tsm.stu_master_stu_info_id
 /* WHERE tu.user_type = 'S' /* Optional */ 

 UNION ALL

SELECT tu.user_id as UserId,
       tei.emp_first_name as FirstName,
       tei.emp_last_name as LastName,
       tu.user_type as UserType 
  FROM users tu 
  JOIN emp_master tem 
    ON tem.em_user_id = tu.user_id 
  JOIN emp_info tei 
    ON tei.emp_info_id = tsm.em_emp_info_id
 /* WHERE tu.user_type = 'E' /* Optional */ 

事实上,你可以做到:

SELECT tsm.stu_master_user_id as UserId,
       tsi.stu_first_name as FirstName,
       tsi.stu_last_name as LastName,
       'S' as UserType 
  FROM stu_master tsm 
    ON tsm.stu_master_user_id = tu.user_id 
  JOIN stu_info tsi 
    ON tsi.stu_info_id = tsm.stu_master_stu_info_id

 UNION ALL

SELECT tem.em_user_id as UserId,
       tei.emp_first_name as FirstName,
       tei.emp_last_name as LastName,
       'E' as UserType 
  FROM emp_master tem 
    ON tem.em_user_id = tu.user_id 
  JOIN emp_info tei 
    ON tei.emp_info_id = tsm.em_emp_info_id 

老实说,我认为你可以重新审视你的架构。你有很多奇怪的事情在继续。

大概一个员工/学生只能有一个信息记录,那么是否需要多对多样式链接表(emp_master / student_master)?

您实际上可以将user_id用作emp_info / student_info表中用户的PK和FK:

  • student - user_id(PK和FK to users),first_name,last_name,...
  • employee - user_id(PK和FK to users),first_name,last_name,...

然后您的查询可能是:

SELECT tu.user_id, ts.first_name, ts.last_name, tu.user_type
  FROM users tu
  JOIN student ts
    ON ts.user_id = tu.user_id
/* WHERE tu.user_type = 'S' /* Optional */        
 UNION ALL
SELECT tu.user_id, te.first_name, te.last_name, tu.user_type
  FROM users tu
  JOIN employee te
    ON te.user_id = tu.user_id
/* WHERE tu.user_type = 'E' /* Optional */        

或:

SELECT user_id, first_name, last_name, 'S' AS user_type
  FROM student
 UNION ALL
SELECT user_id, first_name, last_name, 'E' AS user_type
  FROM employee

如果您考虑将公共字段first_name和last_name移动到users表本身,也值得一提:

- users - user_id, user_type, first_name, last_name

然后最终你会离开:

SELECT user_id, first_name, last_name, user_type  
  FROM users

答案 1 :(得分:3)

你真的很亲密,你甚至不需要工会。

这里有三种使用case语句和一种使用NVL()的方法,一种使用内联视图(如果你不能更改表结构,我会使用内联视图,它&#39 ;应该预先形成最好的。但是,如果要抓取的用户列表足够大,您可能希望在内联视图的每个select语句中添加where子句的附加副本。)

SELECT `user_id` as UserId
, (CASE WHEN `user_type` = 'S' THEN `stu_first_name`
 WHEN `user_type` = 'E' THEN `emp_first_name`  
END) as FirstName
, (CASE WHEN `user_type` = 'S' THEN `stu_last_name` 
      WHEN `user_type` = 'E' THEN `emp_last_name`  
 END) as LastName
, user_type as UserType 
FROM `users`  
LEFT JOIN stu_master tsm ON (stu_master_user_id = user_id AND `user_type` = 'S')
LEFT JOIN stu_info tsi ON (tsm.stu_master_stu_info_id = tsi.stu_info_id)
LEFT JOIN emp_master tem ON (em_user_id = user_id AND `user_type` = 'E')
LEFT JOIN emp_info tei ON (tem.em_id = tei.emp_info_id)
WHERE `user_id` IN (1, 2, 3, 4, 5, 6);



SELECT `user_id` as UserId
, NVL(`stu_first_name`,`emp_first_name`) as FirstName
, NVL(`stu_last_name`,`emp_last_name`) as LastName
, user_type as UserType 
FROM `users`  
LEFT JOIN stu_master tsm ON (stu_master_user_id = user_id AND `user_type` = 'S')
LEFT JOIN stu_info tsi ON (tsm.stu_master_stu_info_id = tsi.stu_info_id)
LEFT JOIN emp_master tem ON (em_user_id = user_id AND `user_type` = 'E')
LEFT JOIN emp_info tei ON (tem.em_id = tei.emp_info_id)
WHERE `user_id` IN (1, 2, 3, 4, 5, 6);

SELECT `user_id` as UserId
, `FirstName` as FirstName
, `LastName`  as LastName
, `user_type` as UserType 
FROM `users`  
LEFT JOIN
(
SELECT 'S' as user_type
, stu_master_user_id as user_id
, stu_first_name as FirstName
, stu_last_name  as LastName
FROM stu_master tsm
INNER JOIN stu_info tsi ON (tsm.stu_master_stu_info_id = tsi.stu_info_id)
UNION ALL
SELECT 'E' as user_type
, em_user_id as user_id
, emp_first_name as FirstName
, emp_last_name  as LastName
FROM emp_master tem 
INNER JOIN emp_info tei ON (tem.em_id = tei.emp_info_id)
) `User_info` USING (user_id, user_type)
WHERE `user_id` IN (1, 2, 3, 4, 5, 6);
;

下面是我用来在sqlfiddle.com中创建虚拟表的代码

CREATE TABLE users
    (`user_id` int, `user_type` varchar(1))
;
insert into users VALUES (1,'A');
insert into users VALUES (2,'E');
insert into users VALUES (3,'E');
insert into users VALUES (4,'S');
insert into users VALUES (5,'S');
insert into users VALUES (6,'S');

CREATE TABLE stu_master
    (`stu_master_id` int,`stu_master_stu_info_id` int,`stu_master_user_id` int)
;

insert into stu_master VALUES (1,1,4);
insert into stu_master VALUES (2,2,5);
insert into stu_master VALUES (3,3,6);
insert into stu_master VALUES (4,4,7);
insert into stu_master VALUES (5,5,8);

CREATE TABLE stu_info
    (`stu_info_id` int,`stu_first_name` varchar(10),`stu_last_name` varchar(10))
;

insert into stu_info VALUES (1,'Student','One');
insert into stu_info VALUES (2,'Student','Two');
insert into stu_info VALUES (3,'Student','Three');
insert into stu_info VALUES (4,'Student','Four');
insert into stu_info VALUES (5,'Student','Five');


CREATE TABLE emp_master
    (`em_id` int,`em_emp_info_id` int,`em_user_id` int)
;
insert into emp_master VALUES (1,1,2);
insert into emp_master VALUES (2,2,3);
insert into emp_master VALUES (3,3,736);
insert into emp_master VALUES (4,4,737);
insert into emp_master VALUES (5,5,738);

CREATE TABLE emp_info
    (`emp_info_id` int,`emp_first_name` varchar(10),`emp_last_name` varchar(10))
;
insert into emp_info VALUES (1,'Employee','One');
insert into emp_info VALUES (2,'Employee','Two');
insert into emp_info VALUES (3,'Employee','Three');
insert into emp_info VALUES (4,'Employee','Four');
insert into emp_info VALUES (5,'Employee','Five');

答案 2 :(得分:1)

您需要比较两个联接中的条件,因为您要将用户表与左连接加入,而您的学生和员工表加入右侧。如果你不比较两个左连接中的条件,它将分别左边有两个表,然后是UNION它们。因此,您将从单一条件获得不必要的记录。

{{1}}