我有一个表“dtr”,其中包含6列,即Name,ACNo,Date,Time,State和Exception。
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个登记入住 然后移动到 第二个循环 - 将获得结账 在办理入住和退房手续之后.. 它现在会去 第3个/最后一个循环 - 将使用第一个和第二个循环的结果范围获得Breaks(具有Out Exception的那个)。
我这样做,所以我可以计算每一对的Out和Outbreak 一(1)班(从办理登机手续到退房)。 之后,我可以计算一(1)班的休息时间/分钟。
我不能仅仅基于日期的转变范围。 becoz如果我这样做,其他休息将在另一个/下一个班次,它与休息日具有相同的登记日期,我无法正确计算或计算它所具有的每一对休息。
但似乎我无法做对。 我该怎么办才能得到正确的结果?或者让循环正确...
<?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]
答案 0 :(得分: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或者更好的像Docii或者ActiveRecord这样的完整ORM,就像Yii所拥有的那样。如果你做任何这些,你会很高兴。
答案 1 :(得分:1)
我可能会做的是在DB端进行所有计算和准备数据(使用相当残酷的查询)然后将其呈现在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脚本:
05/13/2013 - 11:45:18 PM - Check In 05/14/2013 - 12:46:58 AM - Out 05/14/2013 - 12:52:41 AM - Out Back 05/14/2013 - 02:12:50 AM - Out 05/14/2013 - 02:43:11 AM - Out Back 05/14/2013 - 05:46:58 AM - Out 05/14/2013 - 06:22:41 AM - Out Back 05/14/2013 - 06:55:12 AM - Check Out Break Count: 3 Total Mins Of Break: 72 05/14/2013 - 11:47:13 PM - Check In 05/15/2013 - 12:36:28 AM - Out 05/15/2013 - 12:59:11 AM - Out Back 05/15/2013 - 03:12:54 AM - Out 05/15/2013 - 03:33:31 AM - Out Back 05/15/2013 - 06:55:12 AM - Check Out Break Count: 2 Total Mins Of Break: 43