-1

我有一个表“dtr”,其中包含 6 列,即名称、ACNo、日期、时间、状态和异常。

   Name      | ACNo. |    Date   |    Time      |   State    | Exception|
-------------+-------+-----------+--------------+------------+----------+
Johnny Starks| 1220  | 5/13/2013 | 11:45:18 PM  |  Check In  |   OK     |
Johnny Starks| 1220  | 5/14/2013 | 12:46:58 AM  |  Out       |   Out    |
Johnny Starks| 1220  | 5/14/2013 | 12:52:41 AM  |  Out Back  |   Out    |
Johnny Starks| 1220  | 5/14/2013 | 02:12:50 AM  |  Out       |   Out    |
Johnny Starks| 1220  | 5/14/2013 | 02:43:11 AM  |  Out Back  |   Out    |
Johnny Starks| 1220  | 5/14/2013 | 05:46:58 AM  |  Out       |   Out    |
Johnny Starks| 1220  | 5/14/2013 | 06:22:41 AM  |  Out Back  |   Out    |
Johnny Starks| 1220  | 5/14/2013 | 06:55:12 AM  |  Check Out |   OK     |
Johnny Starks| 1220  | 5/14/2013 | 11:47:13 PM  |  Check In  |   OK     |
Johnny Starks| 1220  | 5/15/2013 | 12:36:28 AM  |  Out       |   Out    |
Johnny Starks| 1220  | 5/15/2013 | 12:59:11 AM  |  Out Back  |   Out    |
Johnny Starks| 1220  | 5/15/2013 | 03:12:54 AM  |  Out       |   Out    |
Johnny Starks| 1220  | 5/15/2013 | 03:33:31 AM  |  Out Back  |   Out    |
Johnny Starks| 1220  | 5/15/2013 | 06:55:12 AM  |  Check Out |   OK     |

所以,我想使用下面的代码得到的结果是......或者我希望循环执行的序列......

在第一个循环中-它将获得 1 个签入然后移动到第二个循环-在签入和签出后将获得签出..它现在将进入第三个/最后一个循环-这将是将使用第一个和第二个循环的结果范围获得 Breaks(带有 Out Exception 的那个)。

我这样做是为了计算每一个 (1) 班次中的每一对 Out 和 Outbreak(从签到到签出)。之后,我可以计算一 (1) 个班次的总休息分钟/小时。

我不能仅仅基于日期的班次范围。因为如果我这样做了,其他休息时间将在另一个/下一个班次,该班次的入住日期与休息日期相同,我无法正确计算或计算它所拥有的每一对休息时间。

但似乎我做错了。我应该怎么做才能得到正确的结果?或者让循环正确...

<?php
include 'connection.php';
$checktime='';
$outtime = '';

$isql = mysql_query("Select * from dtr where ACNo = '1220' and 
State = 'Check In'") or die(mysql_error());

while($irow = mysql_fetch_array($isql)){
    $iID = $irow['ACNo'];
    $iDate = $irow['Date'];
    $iTime = $irow['Time'];
    $iState = $irow['State'];

    if($iState == 'Check In'){
        $checktime = $iTime;
        $indate = $iDate;
    }

$osql = mysql_query("Select * from dtr where ACNo = '1220' and 
State = 'Check Out'") or die(mysql_error());

while($orow = mysql_fetch_array($osql)){
    $oID = $orow['ACNo'];
    $oDate = $orow['Date'];
    $oTime = $orow['Time'];
    $oState = $orow['State'];

    if($oState == 'Check Out'){
        $outtime = $oTime;
        $outdate = $oDate;
    }


$bsql = mysql_query("select * from dtr where Exception = 'Out' And Time Between     
'$checktime' and '$outtime'")or die(mysql_error());

while($brow = mysql_fetch_array($bsql)){
    $bID = $brow['ACNo'];
    $bDate = $brow['Date'];
    $bTime = $brow['Time'];
    $bState = $brow['State'];

    echo $bDate.' - ';
    echo $bTime.' ';
    echo $bState.'<br>';
}

}

}
?>

编辑:根据要求..我一直期待或想要的输出是这样的......

 5/13/2013 | 11:45:18 PM  |  Check In  
 5/14/2013 | 12:46:58 AM  |  Out       
 5/14/2013 | 12:52:41 AM  |  Out Back  
 5/14/2013 | 02:12:50 AM  |  Out       
 5/14/2013 | 02:43:11 AM  |  Out Back  
 5/14/2013 | 05:46:58 AM  |  Out       
 5/14/2013 | 06:22:41 AM  |  Out Back  
 5/14/2013 | 06:55:12 AM  |  Check Out
 Break Count : 3
 Total Mins Of Break: [total here]

 5/14/2013 | 11:47:13 PM  |  Check In  
 5/15/2013 | 12:36:28 AM  |  Out       
 5/15/2013 | 12:59:11 AM  |  Out Back  
 5/15/2013 | 03:12:54 AM  |  Out       
 5/15/2013 | 03:33:31 AM  |  Out Back  
 5/15/2013 | 06:55:12 AM  |  Check Out
 Break Count : 2
 Total Mins Of Break: [total here] 
4

2 回答 2

1

您拥有的算法很脆弱,难以理解(可能是由于变量名和嵌套循环),并且易于优化。我会建议一种不同的方法。这将产生您想要的示例输出并解决我提到的问题:

<?php
include 'connection.php';

$q = mysql_query("SELECT * FROM dtr WHERE ACNo = '1220' ORDER BY `Date`, `Time`") or die(mysql_error());

$isIn = false;
$breakDate = NULL;
$breakTime = NULL;
$breakCount = 0;
$breakCumulativeSeconds = 0;
while($dtr = mysql_fetch_object($q))
{
  $logLine = "$dtr->Date | $dtr->Time | $dtr->State\n";

  switch($dtr->State)
  {
    case 'Check In':
      if($isIn)
      {
        throw new LogicException('Two check-ins.');
      }

      $isIn = true;
      echo $logLine;
      break;

    case 'Check Out':
      if(!$isIn)
      {
        throw new LogicException('Check out when not checked in');
      }
      else if(isset($breakDate))
      {
        throw new LogicException('Check out while on break.');
      }

      echo $logLine;
      echo "Break Count: $breakCount\n";
      echo 'Total Mins Of Break: ', number_format($breakCumulativeSeconds / 60, 2), "\n\n";
      $breakCount = $breakCumulativeSeconds = 0;
      $isIn = false;
      break;

    case 'Out':
      if(!$isIn)
      {
        throw new LogicException('Break when not checked in');
      }
      else if(isset($breakDate))
      {
        throw new LogicException('Break start while already on break');
      }

      $breakDate = $dtr->Date;
      $breakTime = $dtr->Time;

      echo $logLine;
      break;

    case 'Out Back':
      if(!isset($breakDate))
      {
        throw new LogicException('Break end while not on break');
      }

      ++$breakCount;
      $breakCumulativeSeconds += (strtotime("$dtr->Date $dtr->Time") - strtotime("$breakDate $breakTime"));
      $breakDate = $breakTime = NULL;

      echo $logLine;
      break;

    default:
      throw new LogicException('Unknown State.');
  }
}
?>

另外,就像有人提到的那样,您应该真正考虑使用 mysqli、PDO 或更好的成熟 ORM,如 Doctrine 或 ActiveRecord,如 Yii 所拥有的。如果你做任何这些,你会很高兴。

于 2013-06-20T07:22:49.387 回答
1

我可能会做的是在数据库端进行所有计算并准备数据(使用相当残酷的查询),然后在 php 中呈现

$acno = 1220;

$sql = 
"SELECT s.n, s.details, b.breaks_count, b.breaks_total
  FROM
(
  SELECT n, GROUP_CONCAT(CONCAT_WS('|', DATE_FORMAT(date, '%m/%d/%Y'), time, state)) details
    FROM
  (
    SELECT @n := IF(state = 'Check In', @n + 1, @n) n, d.*
      FROM dtr d, (SELECT @n := 0, @m := 0) n
     WHERE acno = $acno
  ) a
  GROUP BY n
) s JOIN
(
  SELECT n, COUNT(*) breaks_count, ROUND(SUM(o.secs) / 60) breaks_total
    FROM
  (
    SELECT n, m 
           ,TIME_TO_SEC(
            TIMEDIFF(MIN(CASE WHEN state = 'Out Back' THEN ADDTIME(date, time) END),
                     MIN(CASE WHEN state = 'Out'      THEN ADDTIME(date, time) END))) secs
      FROM
    (
      SELECT @n := IF(state = 'Check In', @n + 1, @n) n, 
             @m := IF(state = 'Out', @m + 1, @m) m,
             d.*
        FROM dtr d, (SELECT @n := 0, @m := 0) n
       WHERE acno = $acno
    ) q
     WHERE state IN('Out', 'Out Back')
     GROUP BY n, m
  ) o
   GROUP BY n
) b ON s.n = b.n";

$result = mysql_query($sql);
if($result === FALSE) {
    die(mysql_error()); // TODO: better error handling
}
//We've done everything on db side so presentation is short and clean
while($row = mysql_fetch_assoc($result)) {
    $details = explode(',', $row['details']);
    foreach ($details as $detail) {
        list($date, $time, $state) = explode('|', $detail);
        echo "$date - $time - $state<br>";
    }
    echo "Break Count: " .$row['breaks_count']."<br>";
    echo "Total Mins Of Break: ".$row['breaks_total']."<br>";
}

这是用于数据库查询的SQLFiddle演示。

根据您的示例数据输出 php 脚本:

2013 年 5 月 13 日 - 晚上 11:45:18 - 入住
2013 年 5 月 14 日 - 上午 12:46:58 - 外出
2013 年 5 月 14 日 - 上午 12:52:41 - 外出返回
2013 年 5 月 14 日 - 上午 02:12:50 - 外出
05/14/2013 - 02:43:11 AM - 外出回来
05/14/2013 - 05:46:58 AM - 出局
05/14/2013 - 06:22:41 AM - 外出回来
05/14/2013 - 06:55:12 AM - 退房
休息次数:3
总休息时间:72
2013 年 5 月 14 日 - 晚上 11:47:13 - 入住
2013 年 5 月 15 日 - 上午 12:36:28 - 外出
2013 年 5 月 15 日 - 上午 12:59:11 - 外出返回
2013 年 5 月 15 日 - 上午 03:12:54 - 外出
2013 年 5 月 15 日 - 上午 03:33:31 - 回来
05/15/2013 - 06:55:12 AM - 退房
休息次数:2
总休息时间:43
于 2013-06-20T19:08:30.667 回答