-1

名前、ACNo、日付、時刻、状態、例外の 6 つの列を含むテーブル「dtr」があります。

   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回のチェックインを取得し、2番目のループに移動します - チェックインとチェックアウトを取得した後にチェックアウトを取得します..3番目/最後のループに移動します - これは1 番目と 2 番目のループの結果の範囲を使用して、Breaks (Out Exception のあるもの) を取得します。

私はこれを行っているので、すべての1シフト(チェックインからチェックアウトまでの範囲)でアウトとアウトブレイクのすべてのペアを計算できます。その後、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

私がおそらく行うことは、すべての計算を行い、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>";
}

これは、db クエリのSQLFiddleデモです。

サンプル データに基づく php スクリプトの出力:

2013/05/13 - 午後 11:45:18 - チェックイン
2013 年 5 月 14 日 - 午前 12:46:58 - アウト
2013 年 5 月 14 日 - 午前 12:52:41 - アウトバック
2013 年 5 月 14 日 - 午前 2 時 12 分 50 秒 - アウト
2013/05/14 - 02:43:11 AM - アウトバック
2013/05/14 - 05:46:58 AM - アウト
2013/05/14 - 06:22:41 AM - アウトバック
2013/05/14 - 06:55:12 AM - チェックアウト
休憩回数: 3
合計休憩時間: 72
2013/05/14 - 午後 11:47:13 - チェックイン
2013 年 5 月 15 日 - 午前 12:36:28 - アウト
2013/05/15 - 12:59:11 AM - アウトバック
2013 年 5 月 15 日 - 午前 3 時 12 分 54 秒 - アウト
2013/05/15 - 03:33:31 AM - アウトバック
2013/05/15 - 06:55:12 AM - チェックアウト
休憩回数: 2
合計休憩時間: 43
于 2013-06-20T19:08:30.667 に答える
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、または Yii のような Doctrine や ActiveRecord のような本格的な ORM を使用することを検討する必要があります。あなたがそれらのいずれかを行うなら、あなたはとても幸せになるでしょう.

于 2013-06-20T07:22:49.387 に答える