问题 合并具有唯一属性的两行


这是我的表的示例输出(time_entries)

user_name| entry_type   | entry_datetime
 User1   |   Time In    | 28-JUL-13  16:40:40
 User1   |   Time Out   | 28-JUL-13  16:40:41
 User2   |   Time In    | 28-JUL-13  16:41:13
 User2   |   Time Out   | 28-JUL-13  16:41:15
 User1   |   Time In    | 27-JUL-13  16:42:30
 User1   |   Time Out   | 27-JUL-13  16:42:34
 User2   |   Time In    | 27-JUL-13  16:43:32
 User2   |   Time Out   | 27-JUL-13  16:43:35

现在我使用了这个查询

SELECT te.user_name, te.entry_name, MAX(te.entry_datetime) AS date
FROM time_entries AS te
GROUP BY te.entry_type, te.user_name

结果是这样的

user_name| entry_type   | entry_datetime
 User1   |   Time In    | 28-JUL-13  16:40:40
 User1   |   Time Out   | 28-JUL-13  16:40:41
 User2   |   Time In    | 28-JUL-13  16:41:13
 User2   |   Time Out   | 28-JUL-13  16:41:15

题: 有没有办法在1行合并用户名和相同名称?并有一个像这样的输出。

user_name|  Date     | Timein   | Timeout
User1    | 28-JUL-13 | 16:40:40 | 16:40:41
User2    | 28-JUL-13 | 16:41:13 | 16:41:15

我有点混淆怎么做。


9129
2017-07-30 06:01


起源

你想在PHP中做到这一点? - DevZer0
呀..我正在使用php ..有可能吗? - bot
在sql端有没有理由不这样做? - Andrius Naruševičius
哦,我的意思是我想在sql中做我的坏事。类似于我的示例查询。 - bot


答案:


我会以这种方式接近它:

  1. 创建一个查询,返回每个用户和日期的“时间”时间。
  2. 创建一个像#1这样的查询,返回每个用户和日期的“超时”时间。
  3. 使用LEFT JOIN将结果合并在一起。

最终结果:

SELECT te.user_name, LEFT(te.entry_datetime, 10) AS entry_date, cin.entry_datetime AS timein, cout.entry_datetime AS timeout
FROM time_entries te
LEFT JOIN (SELECT user_name, LEFT(entry_datetime, 10) AS entry_date, MIN(entry_datetime) AS entry_datetime
    FROM time_entries
    WHERE entry_type = 'Time In'
    GROUP BY user_name, entry_date
) cin ON cin.user_name = te.user_name AND cin.entry_date = LEFT(te.entry_datetime, 9)
LEFT JOIN (SELECT user_name, LEFT(entry_datetime, 10) AS entry_date, MAX(entry_datetime) AS entry_datetime
    FROM time_entries
    WHERE entry_type = 'Time Out'
    GROUP BY user_name, entry_date
) cout ON cout.user_name = te.user_name AND cout.entry_date = LEFT(te.entry_datetime, 10)
GROUP BY te.user_name, entry_date;

演示

顺便说一下,我正在使用 LEFT() 这是因为您的列不包含MySQL理解的实际日期格式。


6
2017-07-30 06:53



谢谢伙计..你的解决方案正在运行,但仍然需要权衡,这是最好的解决方案,因为这里的所有解决方案都有效。 - bot
@bot当特定日期缺少“时间进入”或“超时”条目时会有所不同。我的回答是 NULL 对于那些缺少的条目,我认为这是正确的行为。 - Ja͢ck
呀..我注意到了。与其他人的答案相比,这给它一个独特的功能。谢谢。 :) - bot
当用户在一天内有多个条目时,这也不起作用。 - Ruben
@Ruben应该,因为两个子查询都有 group by。你指的是特别的东西吗? - Ja͢ck


那这个呢?

select
user_name,
date(entry_datetime) as date,
min(entry_datetime) as Timein,
max(entry_datetime) as Timeout
from (
  SELECT te.user_name, te.entry_name, MAX(te.entry_datetime) AS date
  FROM time_entries AS te
  GROUP BY te.entry_type, te.user_name) src
group by user_name, date

3
2017-07-30 06:12



SELECT te.user_name, te.entry_name, MAX(te.entry_datetime) AS date FROM time_entries AS te GROUP BY te.entry_type, te.user_name 如果您从中选择数据,我认为最大和最小日期始终相同 - Amit Singh
这将在“字段列表”中返回错误消息“未知列”“entry_datetime” - bot
@bot从子查询写入表名称只是它将适用于此数据集而不是子表查询表的表格 - Amit Singh
@bot用MAX(te.entry_datetime)AS entry_datetime替换子查询部分 - StanislavL
谢谢伙计..你的解决方案正在运行,但仍然需要权衡,这是最好的解决方案,因为这里的所有解决方案都有效。 - bot


这是一个关于如何处理数据的php端解决方案。

function transformArray($data) {
   $final = array();
   foreach ($data as $key => $row) {
      if (!isset($final[$row['u']])) $final[$row['u']] = array('user' => $row['u']);
      $final[$row['u']][$row['t']] = date("H:i:s", strtotime($row['entrydatetime']));
      $final[$row['u']]['date'] = date("d:M:y", strtotime($row['entrydatetime']));
   }

   return $final;
}

您可以向它传递一个看起来像这样的数据集,您可以将字段名称调整为nessecery。

$data = array(
         array('u' => 'user1', 't' => 'TimeIn', 'entrydatetime' => '28-JUL-13  16:40:40'),
         array('u' => 'user1', 't' => 'TimeOut', 'entrydatetime' => '28-JUL-13  16:40:40'),
         array('u' => 'user2', 't' => 'TimeIn', 'entrydatetime' => '28-JUL-13  16:40:40'),
         array('u' => 'user2', 't' => 'TimeOut', 'entrydatetime' => '28-JUL-13  16:40:40')
);

1
2017-07-30 06:29



谢谢伙计..你的解决方案正在运行,但仍然需要权衡,这是最好的解决方案,因为这里的所有解决方案都有效。 - bot


这将完成工作:

SELECT te.user_name,DATE(te.entry_datetime) as Date,te.entry_datetime AS TimeIn,te2.entry_datetime AS TimeOut
FROM time_entries te
JOIN time_entries te2 ON te.user_name=te2.user_name AND te2.entry_type="Time Out" AND
  te2.entry_datetime=
  (
    SELECT 
      entry_datetime
    FROM 
      time_entries
    WHERE entry_type='Time Out' AND user_name=te.user_name AND entry_datetime > te.entry_datetime
    ORDER BY 
      ABS(TIMESTAMPDIFF(SECOND, te.entry_datetime, `entry_datetime`))
    LIMIT 1
  )
WHERE te.entry_type="Time In";

编辑:一点解释:

它为TimeIn部分选择user_name,date部分和entry_datetime。然后它连接在同一个表上以获取Time Out datetime部分。它通过选择具有相同user_name的类型“Time Out”的条目和最接近Time In datetime的日期来完成此操作。


1
2017-07-30 06:29



谢谢伙计..你的解决方案正在运行,但仍然需要权衡,这是最好的解决方案,因为这里的所有解决方案都有效。 - bot
别客气。 - Ruben


select
user_name,
dATE(entry_datetime) AS date1,
min(entry_datetime) as Timein,
max(entry_datetime) as Timeout
from time_entries
group by user_name, date1

SqlFiddleDemo

对于每个Time_In,此查询将正常工作   相应的超时。并且每个新的一天入场类型都应该   从time_in开始


1
2017-07-30 07:14



但是,当用户在1天内有多个条目时,这将不起作用。 - Ruben
@Ruben查看更新后的答案.....如果符合该要求,无论用户进出时间多长时间,它都会给出正确的结果 - Amit Singh