mysql:当join不匹配时需要null字段

时间:2014-07-29 22:01:21

标签: mysql

我在MySQL上使用这两个表格。

select emp_id, contrato_id,date from organização_rh;
+--------+-------------+------------+
| emp_id | contrato_id | date       |
+--------+-------------+------------+
|      1 |           1 | 2000-01-01 |
|      1 |           2 | 2000-01-10 |
|      1 |           3 | 2000-02-01 |
|      2 |           1 | 1999-01-01 |
+--------+-------------+------------+

select id, codigo from contratotipo;
+----+---------------+
| id | codigo        |
+----+---------------+
|  2 | determinado   |
|  3 | fim           |
|  1 | indeterminado |
+----+---------------+

我要做的是以一种员工没有签订合同的方式加入他们,将日期字段设置为NULL。也就是说,我希望输出如下:

+--------+-------------+------------+
| emp_id | contrato_id | date       |
+--------+-------------+------------+
|      1 |           1 | 2000-01-01 |
|      1 |           2 | 2000-01-10 |
|      1 |           3 | 2000-02-01 |
|      2 |           1 | 1999-01-01 |
|      2 |           2 | NULL       |
|      2 |           3 | NULL       |
+--------+-------------+------------+

我尝试过不同的连接但无效,到目前为止,它们都没有显示我在日期字段中有一个NULL值的行。所以,例如,如果我运行

SELECT emp_id,contrato_id, date 
FROM organização_rh as o right outer JOIN contratotipo c
ON o.contrato_id = c.id;

当行不匹配时,我没有得到任何NULL值。

 +--------+-------------+------------+
 | emp_id | contrato_id | date       |
 +--------+-------------+------------+
 |      1 |           3 | 2000-02-01 |
 |      1 |           2 | 2000-01-10 |
 |      1 |           1 | 2000-01-01 |
 |      2 |           1 | 1999-01-01 |
 +--------+-------------+------------+

任何帮助都将非常感谢!!

@John Ruddell感谢您的帮助。 我想出了这个不太优雅的解决方案,因为它使用游标,但它适用于任意数量的员工和合同。您的解决方案似乎更加轻松,因为一切只适合一个查询。但是,我无法将其改编为更一般的案例。

BEGIN
declare var_contrato_id int unsigned;
declare contrato_finished int default 0;


DECLARE contrato_cursor CURSOR FOR SELECT id FROM contratotipo;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET contrato_finished = 1;  
OPEN contrato_cursor;

drop table if exists temp_sp_rh_turnover;
CREATE TEMPORARY TABLE temp_sp_rh_turnover AS (select distinct org_id, emp_id, cast( 0 AS unsigned) as contrato_id, cast('1000-1-1' as date) as data from organização_rh where emp_id=-1);

conts: LOOP

    FETCH contrato_cursor INTO var_contrato_id;
    IF contrato_finished = 1 THEN 
        LEAVE conts;
    END IF;
    insert into temp_sp_rh_turnover
    select distinct org_id, emp_id, var_contrato_id, NULL from organização_rh;

end loop;


select
    t.org_id, t.emp_id, t.contrato_id, o.data
from
    temp_sp_rh_turnover as t
left join
    organização_rh as o
on
    t.org_id = o.org_id and
    t.emp_id = o.emp_id and
    t.contrato_id = o.contrato_id;



drop table if exists temp_sp_rh_turnover;
END

4 个答案:

答案 0 :(得分:0)

将表连接到自身。类似的东西:

select emp_id, contrato_id,date from organização_rh as a
JOIN
SELECT DISTINCT contrato_id FROM organização_rh as b
WHERE a.contrato_id = b.contrato_id

应该有用。

或者你可以

select emp_id, contrato_id,date from organização_rh as a
JOIN
select DISTINCT id from contratotipo as b
WHERE a.contrato_id = b.id

如果那更符合您的喜好。

答案 1 :(得分:0)

您遇到麻烦的原因是,如果没有列出所有员工的第三个表,您就无法做到这一点。

您可能认为可以使用

获取此信息
select distinct emp_id from organização_rh

但这不包括员工未签署任何合同的情况。当然,您希望该员工出现在所有合同的空日期输出中。

创建一个employee表,然后连接应该是显而易见的。

答案 2 :(得分:0)

在mysql中做这样的事情并不容易,这需要大量的手工工作。从我的理解,你想在你的另一个表中每行显示一个新行..

含义 对于表o中的每个 emp_id,您希望有3行与之相关,其中一行与表c中的三行相关。

现在做类似的事情并不简单,因为没有办法手动添加行,除非您正在进行插入或一堆联合。因此,使用此数据集(我假设与您使用的数据相比较小),您可以获得这样的预期结果。

SET @row_num := 1;

INSERT INTO organização_rh (emp_id, contrato_id, date)
SELECT 
    emp_id, @ROW_NUM := @ROW_NUM + 1, NULL
FROM organização_rh
WHERE emp_id IN
(   SELECT emp_id 
    FROM organização_rh
    GROUP BY emp_id
    HAVING COUNT(*) < 3
)
AND @ROW_NUM < 3;

运行此插入查询两次,我将为您提供所需的输出。

输出:

23:20:25    set @row_num := 1   0 row(s) affected   0.000 sec
23:20:30    INSERT INTO organização_rh (emp_id, contrato_id, date) SELECT      emp_id, @ROW_NUM := @ROW_NUM + 1, NULL FROM organização_rh WHERE emp_id IN ( SELECT emp_id   FROM organização_rh  GROUP BY emp_id  HAVING COUNT(*) < 3 ) AND @ROW_NUM < 3    1 row(s) affected Records: 1  Duplicates: 0  Warnings: 0    0.001 sec
23:20:31    INSERT INTO organização_rh (emp_id, contrato_id, date) SELECT      emp_id, @ROW_NUM := @ROW_NUM + 1, NULL FROM organização_rh WHERE emp_id IN ( SELECT emp_id   FROM organização_rh  GROUP BY emp_id  HAVING COUNT(*) < 3 ) AND @ROW_NUM < 3    1 row(s) affected Records: 1  Duplicates: 0 Warnings: 0 0.001 sec
23:20:32    INSERT INTO organização_rh (emp_id, contrato_id, date) SELECT      emp_id, @ROW_NUM := @ROW_NUM + 1, NULL FROM organização_rh WHERE emp_id IN ( SELECT emp_id   FROM organização_rh  GROUP BY emp_id  HAVING COUNT(*) < 3 ) AND @ROW_NUM < 3    0 row(s) affected Records: 0  Duplicates: 0  Warnings: 0    0.002 sec

如果您注意到我最后一次尝试这样做,就不会这样做,因为行数最大化了。这将是一些手工劳动,但它基本上只是在mysql中完成它的唯一方法。

插入后

是结果集。

+-------+---------------+---------------+
|emp_id |  contrato_id, |      date     |
+-------+---------------+---------------+
|'1',   |      '1',     |   '2000-01-01'|
|'1',   |      '2',     |   '2000-01-10'|
|'1',   |      '3',     |   '2000-02-01'|
|'2',   |      '1',     |   '1999-01-01'|
|'2',   |      '2',     |    NULL       |
|'2',   |      '3',     |    NULL       |
+-------+---------------+---------------+

注意:这是用于更新表格。如果你想只是一个带有这个输出的查询,你需要为每一个并不真正推荐的新行联合。说实话,你需要修复你的表结构。添加一个您可以进行笛卡尔积加入的列或其他内容。

无论如何这里是联合查询。

SELECT emp_id, contrato_id, date FROM organização_rh
CROSS JOIN(SELECT @ROW_NUM := 0)t
UNION ALL
SELECT 
    emp_id, @ROW_NUM := @ROW_NUM + 1, NULL
FROM
    organização_rh
WHERE emp_id IN
(   SELECT emp_id 
    FROM organização_rh
    GROUP BY emp_id
    HAVING COUNT(*) < 3
)
AND @ROW_NUM < 3
UNION ALL 
SELECT 
    emp_id, @ROW_NUM := @ROW_NUM + 1, NULL
FROM
    organização_rh
WHERE emp_id IN
(   SELECT emp_id 
    FROM organização_rh
    GROUP BY emp_id
    HAVING COUNT(*) < 3
)
AND @ROW_NUM < 3;

OUTPUT 再次与插入

相同
+-------+---------------+---------------+
|emp_id |  contrato_id, |      date     |
+-------+---------------+---------------+
|'1',   |      '1',     |   '2000-01-01'|
|'1',   |      '2',     |   '2000-01-10'|
|'1',   |      '3',     |   '2000-02-01'|
|'2',   |      '1',     |   '1999-01-01'|
|'2',   |      '2',     |    NULL       |
|'2',   |      '3',     |    NULL       |
+-------+---------------+---------------+

答案 3 :(得分:0)

@John Ruddell

这适用于原始值。 我添加了一个新员工:emp_id = 3,contrato_id = 1,date = 2001-1-1。如果我运行查询,我会得到合同3(对于emp_id = 3)。

|emp_id|contrato_id|   date     |
+------+-----------+------------+
|'1',  | '1',      |'2000-01-01'|
|'1',  | '2',      |'2000-01-10'|
|'1',  | '3',      |'2000-02-01'|
|'2',  | '1',      |'1999-01-01'|
|'2',  | '2',      | NULL       |
|'2',  | '3',      | NULL       |
|'3',  | '1',      |'2001-01-01'|
|'3',  | '2',      | NULL       |

我是否必须运行查询:

SELECT 
    emp_id, @ROW_NUM := @ROW_NUM + 1, NULL
FROM
    organização_rh

WHERE emp_id IN
 (   SELECT emp_id 
    FROM organização_rh
    GROUP BY emp_id
    HAVING COUNT(*) < 3
)
AND @ROW_NUM < 3
重置@ROW_NUM后,每个用户