php - 简单输入/输出记录的复杂选择查询

标签 php mysql select row

我正在制作一个简单的时间进出系统。我有 3 对输入/输出。

emp_id    td_id    status     timestamp          remarks
  35        1        in   2013-12-19 10:15:09     late
  35        2        out  2013-12-19 12:00:23     example
  35        3        in   2013-12-19 13:00:23
  35        4        out  2013-12-19 16:01:47
  35        5        in   2013-12-19 18:01:17
  35        6        out  2013-12-19 22:01:07
  35        7        in   2013-12-20 10:00:12

这是我的查询:

 SELECT a1.emp_id, a1.status, a1.timestamp, a2.status, a2.timestamp, a3.status, a3.timestamp, a4.status, a4.timestamp,  a5.status, a5.timestamp, a6.status, a6.timestamp
 FROM overallrec a1
 LEFT JOIN overallrec a2 ON a2.emp_id = a1.emp_id
 AND a2.status =  'out'
 LEFT JOIN overallrec a3 ON a3.emp_id = a1.emp_id
 AND a3.status =  'in'
 AND a3.timestamp <> a1.timestamp
 LEFT JOIN overallrec a4 ON a4.emp_id = a1.emp_id
 AND a4.status =  'out'
 AND a4.timestamp <> a2.timestamp
 LEFT JOIN overallrec a5 ON a5.emp_id = a1.emp_id
 AND a5.status =  'in'
 AND a5.timestamp <> a3.timestamp
 LEFT JOIN overallrec a6 ON a6.emp_id = a1.emp_id
 AND a6.status =  'in'
 AND a6.timestamp <> a4.timestamp
 WHERE a1.status =  'in'

这是我的结果:

emp_id    status     timestamp      status     timestamp       status     timestamp      status     timestamp       status     timestamp       status     timestamp
  35       in   2013-12-19 10:15:09  out  2013-12-19 12:00:23   in   2013-12-19 13:00:23   out  2013-12-19 16:01:47   in   2013-12-19 18:01:17   out  2013-12-19 22:01:07
  35       in   2013-12-20 10:00:12  out  2013-12-19 12:00:23   in   2013-12-19 13:00:23   out  2013-12-19 16:01:47   in   2013-12-19 18:01:17   out  2013-12-19 22:01:07

请注意,第 2 行的第一个“in”时间戳值是另一个日期,但下一个状态时间戳和很快会从前一个日期开始重复。我希望它在仍然为空时显示 null,而不是复制前一个日期的值。换句话说,它应该在日期更改时生成另一行。

附加备注:当我在每个输入处添加备注时,它将在表结果中连接起来。我希望它是这样的:

 emp_id    status     timestamp      status     timestamp       status     timestamp        status     timestamp       status     timestamp       status     timestamp      remarks
  35       in   2013-12-19 10:15:09  out  2013-12-19 12:00:23   in   2013-12-19 13:00:23   out  2013-12-19 16:01:47   in   2013-12-19 18:01:17   out  2013-12-19 22:01:07   "Late, Example"
  35       in   2013-12-20 10:00:12  null         null            null          null         null          null         null         null            null          null    "Straight time"

我应该如何处理我的查询?或者,如果不使用查询,还有什么?

最佳答案

已更改答案,我忘记按时间戳 1 订购,这是将照顾多名员工的最终版本 :) sqlFiddle

SELECT T1.emp_id,T1.status1 as status1,T1.timestamp1 as timestamp1,
                 T1.status2 as status2,T1.timestamp2 as timestamp2,
                 T2.status1 as status3,T2.timestamp1 as timestamp3,
                 T2.status2 as status4,T2.timestamp2 as timestamp4,
                 T3.status1 as status5,T3.timestamp1 as timestamp5,
                 T3.status2 as status6,T3.timestamp2 as timestamp6
FROM
  (SELECT * FROM
    (SELECT IF(((@row+1)=4) OR (@prevEmpId<>a1.emp_id),@row:=1,@row:=@row+1) as row,a1.emp_id,a1.status as status1,a1.timestamp as timestamp1,
             'out' as status2,
              @prevEmpId:=a1.emp_id,
       (SELECT min(timestamp) as timestamp2
        FROM overallrec a2
        WHERE a2.timestamp > a1.timestamp
          AND a2.emp_id = a1.emp_id
          AND a2.status = 'out') as timestamp2
        FROM overallrec a1,(SELECT @row:=0,@prevEmpId:=0)r
        WHERE a1.status = 'in'
     ORDER BY a1.emp_id,timestamp1
    )T100
    WHERE row=1
  )T1
LEFT JOIN
 (SELECT * FROM
   (SELECT IF(((@row+1)=4) OR (@prevEmpId<>a1.emp_id),@row:=1,@row:=@row+1) as row,a1.emp_id,a1.status as status1,a1.timestamp as timestamp1,
             'out' as status2,
              @prevEmpId:=a1.emp_id,
       (SELECT min(timestamp) as timestamp2
        FROM overallrec a2
        WHERE a2.timestamp > a1.timestamp
          AND a2.emp_id = a1.emp_id
          AND a2.status = 'out') as timestamp2
        FROM overallrec a1,(SELECT @row:=0,@prevEmpId:=0)r
        WHERE a1.status = 'in'
     ORDER BY a1.emp_id,timestamp1
   )T200 
   WHERE row=2
 )T2
ON T1.emp_id = T2.emp_id AND DATE_FORMAT(T2.timestamp1,'%Y-%m-%d') = DATE_FORMAT(T1.timestamp1,'%Y-%m-%d')
LEFT JOIN
 (SELECT * FROM
     (SELECT IF(((@row+1)=4) OR (@prevEmpId<>a1.emp_id),@row:=1,@row:=@row+1) as row,a1.emp_id,a1.status as status1,a1.timestamp as timestamp1,
             'out' as status2,
              @prevEmpId:=a1.emp_id,
       (SELECT min(timestamp) as timestamp2
        FROM overallrec a2
        WHERE a2.timestamp > a1.timestamp
          AND a2.emp_id = a1.emp_id
          AND a2.status = 'out') as timestamp2
        FROM overallrec a1,(SELECT @row:=0,@prevEmpId:=0)r
        WHERE a1.status = 'in'
     ORDER BY a1.emp_id,timestamp1
     )T300 
  WHERE row=3
 )T3
ON T1.emp_id = T3.emp_id AND DATE_FORMAT(T3.timestamp1,'%Y-%m-%d') = DATE_FORMAT(T1.timestamp1,'%Y-%m-%d')

但是,如果员工在一天打卡然后第二天打卡下类,则此查询将不起作用,因为它使用了当天的支票以便 LEFT JOIN

OP 要求一个 View ,但 mySQL 中的 View 不允许变量,所以我尝试编写一个不同的查询(不使用变量),例如这个(sqlFiddle)

SELECT T4.emp_id,T4.status1,T4.timestamp1,T4.status2,T4.timestamp2,
   T4.status3,T4.timestamp3,T4.status4,T4.timestamp4,T4.status5,T4.timestamp5,
   'out' as status6,
   (SELECT min(timestamp)
    FROM overallrec a
    WHERE a.timestamp > T4.timestamp5
      AND a.emp_id = T4.emp_id
      AND a.status = 'out') as timestamp6
  FROM
  (SELECT T3.emp_id,T3.status1,T3.timestamp1,T3.status2,T3.timestamp2,
   T3.status3,T3.timestamp3,T3.status4,T3.timestamp4,
   'in' as status5,
  (SELECT min(timestamp)
    FROM overallrec a
    WHERE a.timestamp > T3.timestamp4
      AND a.emp_id = T3.emp_id
      AND a.status = 'in') as timestamp5
  FROM
  (SELECT T2.emp_id,T2.status1,T2.timestamp1,T2.status2,T2.timestamp2,
   T2.status3,T2.timestamp3,
   'out' as status4,
  (SELECT min(timestamp)
    FROM overallrec a
    WHERE a.timestamp > T2.timestamp3
      AND a.emp_id = T2.emp_id
      AND a.status = 'out') as timestamp4
  FROM
  (SELECT T1.emp_id,T1.status1,T1.timestamp1,T1.status2,T1.timestamp2,
        'in' as status3,
    (SELECT min(timestamp)
    FROM overallrec a
    WHERE a.timestamp > T1.timestamp2
      AND a.emp_id = T1.emp_id
      AND a.status = 'in') as timestamp3
  FROM
   (SELECT a1.emp_id,a1.status as status1,a1.timestamp as timestamp1,
         'out' as status2,
   (SELECT min(timestamp) as timestamp2
    FROM overallrec a2
    WHERE a2.timestamp > a1.timestamp
      AND a2.emp_id = a1.emp_id
      AND a2.status = 'out') as timestamp2
    FROM overallrec a1
    WHERE a1.status = 'in'
          AND NOT EXISTS (SELECT 1 FROM overallrec e
                                   WHERE e.timestamp < a1.timestamp
                                     AND e.emp_id = a1.emp_id
                                    AND DATE_FORMAT(e.timestamp,'%Y-%m-%d') = 
                                        DATE_FORMAT(a1.timestamp,'%Y-%m-%d'))
   )T1
   )T2
   )T3
   )T4;

不幸的是,mySQL View 不允许子查询(子查询不能在 View 的 FROM 子句中使用。) 但是 mySQL 允许在 View 之上创建 View ,所以这里是创建的 View ( sqlFiddle )

CREATE VIEW T100 AS
SELECT a1.emp_id,a1.status as status1,a1.timestamp as timestamp1,
         'out' as status2,
   (SELECT min(timestamp) as timestamp2
    FROM overallrec a2
    WHERE a2.timestamp > a1.timestamp
      AND a2.emp_id = a1.emp_id
      AND a2.status = 'out') as timestamp2
    FROM overallrec a1
    WHERE a1.status = 'in'
          AND NOT EXISTS (SELECT 1 FROM overallrec e
                                   WHERE e.timestamp < a1.timestamp
                                     AND e.emp_id = a1.emp_id
                                    AND DATE_FORMAT(e.timestamp,'%Y-%m-%d') = 
                                        DATE_FORMAT(a1.timestamp,'%Y-%m-%d'));

CREATE VIEW T200 AS
SELECT T1.emp_id,T1.status1,T1.timestamp1,T1.status2,T1.timestamp2,
        'in' as status3,
    (SELECT min(timestamp)
    FROM overallrec a
    WHERE a.timestamp > T1.timestamp2
      AND a.emp_id = T1.emp_id
      AND a.status = 'in') as timestamp3
  FROM T100 AS T1;

CREATE VIEW T300 AS
SELECT T2.emp_id,T2.status1,T2.timestamp1,T2.status2,T2.timestamp2,
   T2.status3,T2.timestamp3,
   'out' as status4,
  (SELECT min(timestamp)
    FROM overallrec a
    WHERE a.timestamp > T2.timestamp3
      AND a.emp_id = T2.emp_id
      AND a.status = 'out') as timestamp4
  FROM T200 AS T2;

CREATE VIEW T400 AS
SELECT T3.emp_id,T3.status1,T3.timestamp1,T3.status2,T3.timestamp2,
   T3.status3,T3.timestamp3,T3.status4,T3.timestamp4,
   'in' as status5,
  (SELECT min(timestamp)
    FROM overallrec a
    WHERE a.timestamp > T3.timestamp4
      AND a.emp_id = T3.emp_id
      AND a.status = 'in') as timestamp5
  FROM T300 AS T3; 

CREATE VIEW myFinalView AS
SELECT T4.emp_id,T4.status1,T4.timestamp1,T4.status2,T4.timestamp2,
   T4.status3,T4.timestamp3,T4.status4,T4.timestamp4,T4.status5,T4.timestamp5,
   'out' as status6,
  (SELECT min(timestamp)
    FROM overallrec a
    WHERE a.timestamp > T4.timestamp5
      AND a.emp_id = T4.emp_id
      AND a.status = 'out') as timestamp6
  FROM T400 AS T4; 

所以我们有一个名为 myFinalView 的 VIEW :)

这是一个带有注释的 myFinalView(检查 sqlFiddle with remarks in the VIEW)

关于php - 简单输入/输出记录的复杂选择查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20672754/

相关文章:

mysql - GROUP_CONCAT 显示所有记录

postgresql - 在 postgresql 中将两个 select 语句添加到一个 insert into 语句中

javascript - $(this) 表单选择的值,具有相同字段名称的许多表单

php - preg_match,是什么导致了错误?

php - 使用 PHP SSH 连接

php - 使用 UPDATE 时,MySQL 将列设置为变量值的正确方法是什么?

mysql - 如何向mysql表中插入数据?

php - 如何从 php 中检索值?

php - 在 PHP 中使用来自正则表达式本身的正则表达式变量

mysql - 为什么mysql在使用 View 时忽略索引