使用GROUP_CONCAT更新多个列不能按预期工作

时间:2016-10-01 01:13:01

标签: mysql group-concat

帮助想要的人!我有一个存储的precedure,用于从另一个表中更新日历样式表的列。第二个记录应存储在按日期和个人分组的日历中,但是我无法在一个UPDATE句子中实现;我不得不进行这些丑陋的逐列更新。如果您有任何想法,我们将不胜感激。代码如下:

DECLARE thisYearMonth VARCHAR(7);
SET thisYearMonth = '2016-09';

UPDATE calendar CAL
INNER JOIN (
    SELECT checkinout.userid,
        checkinout.checktime,
        GROUP_CONCAT(checkinout.checktime) ORDER BY checkinout.id SEPARATOR ' | ') AS checktime
    FROM checkinout
    INNER JOIN calendar ON calendar.userid = checkinout.userid
    WHERE checkinout.userid = calendar.userid
        AND DATE(checktime) = CONCAT(thisYearMonth, '-', '01')
    GROUP BY userid
) CHK ON CHK.userid = CAL.userid 
SET CAL.day1 = CHK.checkstatus;

UPDATE calendar CAL
INNER JOIN (
    SELECT checkinout.userid,
        checkinout.checktime,
        GROUP_CONCAT(checkinout.checktime ORDER BY checkinout.id SEPARATOR ' | ') AS checktime
    FROM checkinout
    INNER JOIN calendar ON calendar.userid = checkinout.userid
    WHERE checkinout.userid = calendar.userid
        AND DATE(checktime) = CONCAT(thisYearMonth, '-', '02')
    GROUP BY userid
) CHK ON CHK.userid = CAL.userid 
SET CAL.day2 = CHK.checkstatus;

等到第n天。问题是我如何让它像一个UPDATE一样工作,它不会在所有重新生成的日历行中重复与行“day1”相同的值,即day1变为10:00,day2变为10:00,依此类推。以下是生成此行为的代码:

UPDATE calendar CAL
INNER JOIN (
    SELECT checkinout.userid,
        checkinout.checktime,
        GROUP_CONCAT(checkinout.checktime) ORDER BY checkinout.id SEPARATOR ' | ') AS checktime
    FROM checkinout
    INNER JOIN calendar ON calendar.userid = checkinout.userid
    WHERE checkinout.userid = calendar.userid
        AND DATE(checktime) = CONCAT(thisYearMonth, '-', '01')
    GROUP BY userid
) CHK ON CHK.userid = CAL.userid 
SET CAL.day1 = CHK.checkstatus,
    CAL.day2 = CHK.checkstatus,
    CAL.day3 = CHK.checkstatus
...;
编辑:根据Gordon Linoff的说法,这可以使用条件聚合来实现,但是它每行只会带一条记录而不是每天都对应每个用户ID的所有记录。

像这样:

Results using conditional aggregation

预期结果:

Result updating row by row individually

我在下面的代码中发布此示例数据,以便您验证我的结果

DROP TABLE IF EXISTS tmp_checkinout;

CREATE TEMPORARY TABLE tmp_checkinout
 (`id` int, `userid` int, `checktime` datetime, `checkstatus` varchar(8));

INSERT INTO tmp_checkinout
 (`id`, `userid`, `checktime`, `checkstatus`)
VALUES
 (1 , 3, '2016-8-1 07:49:23', 'SHRP'),
 (2 , 2, '2016-8-1 08:01:40', 'SHRP'),
 (3 , 1, '2016-8-1 08:49:07', 'SHRP'),
 (4 , 5, '2016-8-1 09:14:19', 'LATE'),
 (5 , 3, '2016-8-2 07:48:06', 'SHRP'),
 (6 , 2, '2016-8-2 08:04:03', 'SHRP'),
 (7 , 4, '2016-8-2 08:04:12', 'SHRP'),
 (8 , 1, '2016-8-2 08:49:07', 'SHRP'),
 (9 , 5, '2016-8-2 09:10:31', 'TOLR'),
 (10, 3, '2016-8-2 10:40:16', 'EXTN'),
 (11, 3, '2016-8-3 07:48:32', 'SHRP'),
 (12, 2, '2016-8-3 08:05:34', 'SHRP'),
 (13, 4, '2016-8-3 08:12:23', 'LATE'),
 (14, 5, '2016-8-3 09:08:52', 'TOLR'),
 (15, 1, '2016-8-3 10:23:41', 'EXTN'),
 (16, 3, '2016-8-4 07:49:15', 'SHRP'),
 (17, 2, '2016-8-4 08:05:39', 'SHRP'),
 (18, 1, '2016-8-4 08:36:44', 'SHRP'),
 (19, 4, '2016-8-4 08:07:22', 'TOLR'),
 (20, 5, '2016-8-4 09:22:34', 'LATE'),
 (21, 3, '2016-8-5 07:51:42', 'SHRP'),
 (22, 4, '2016-8-5 08:11:33', 'LATE'),
 (23, 2, '2016-8-5 08:16:54', 'LATE'),
 (24, 1, '2016-8-5 08:53:20', 'SHRP'),
 (25, 5, '2016-8-5 09:26:02', 'LATE'),
 (26, 3, '2016-8-2 10:52:44', 'EXTN')
;

DROP TABLE IF EXISTS tmp_calendar;

CREATE TEMPORARY TABLE tmp_calendar
 (`userid` int, `day1` varchar(40), `day2` varchar(40), `day3` varchar(40), `day4` varchar(40), `day5` varchar(40));

INSERT INTO tmp_calendar
 (`userid`)
VALUES (1), (2), (3), (4), (5);

使用Gordon Linoff的答案,这是生成结果的代码,如图1所示:

UPDATE tmp_calendar AS cal
INNER JOIN
 (SELECT id, userid,
  CASE WHEN DAY(checktime) = 1 THEN CONCAT('ID:', id, ', ', checkstatus, ', ', checktime) ELSE NULL END AS timeandstatus_01,
  CASE WHEN DAY(checktime) = 2 THEN CONCAT('ID:', id, ', ', checkstatus, ', ', checktime) ELSE NULL END AS timeandstatus_02,
  CASE WHEN DAY(checktime) = 3 THEN CONCAT('ID:', id, ', ', checkstatus, ', ', checktime) ELSE NULL END AS timeandstatus_03,
  CASE WHEN DAY(checktime) = 4 THEN CONCAT('ID:', id, ', ', checkstatus, ', ', checktime) ELSE NULL END AS timeandstatus_04,
  CASE WHEN DAY(checktime) = 5 THEN CONCAT('ID:', id, ', ', checkstatus, ', ', checktime) ELSE NULL END AS timeandstatus_05
 FROM tmp_checkinout
 WHERE DATE_FORMAT(checktime, '%Y-%m') = '2016-08'
 ORDER BY id ASC) AS chk ON chk.userid = cal.userid
SET cal.day1 = chk.timeandstatus_01,
 cal.day2 = chk.timeandstatus_02,
 cal.day3 = chk.timeandstatus_03,
 cal.day4 = chk.timeandstatus_04,
 cal.day5 = chk.timeandstatus_05
WHERE cal.userid = chk.userid;

感谢任何指针: - )

1 个答案:

答案 0 :(得分:0)

我认为你需要子查询中的条件聚合:

UPDATE calendar CAL INNER JOIN
       (SELECT ch.userid, ch.checktime,
               GROUP_CONCAT(CASE WHEN DAY(checktime) = 01 THEN ch.checktime END ORDER BY ch.id SEPARATOR ' | ') AS checktime_01,
               GROUP_CONCAT(CASE WHEN DAY(checktime) = 02 THEN ch.checktime END ORDER BY ch.id SEPARATOR ' | ') AS checktime_02,
               . . .
        FROM checkinout ch INNER JOIN
             calendar ca
             ON ca.userid = ch.userid
        WHERE date_format(checktime, '%Y-%m') = thisYearMonth
        GROUP BY userid
       ) CHK 
       ON CHK.userid = CAL.userid 
    SET CAL.day1 = CHK.checkstatus_01,
        CAL.day2 = CHK.checkstatus_02;