sql >> データベース >  >> RDS >> Mysql

テーブルから欠落している行を返す方法-従業員不在レポート

    「不在」がemp_txに行が表示されないこととして定義されている場合 特定のempcodeのテーブル 特定の日付(date =深夜から深夜24時間)、および...

    emp_txにトランザクションがない日付に「不在」を表示しないことが許容される場合 その日付のテーブル(つまり、その日付にすべてのempcodeが存在しない日付を除外する)、次に...

    次のようなクエリを使用して、指定した結果セットの最初の4列を取得できます:(未テスト)

    SELECT m.empcode     AS `EmpCode` 
         , m.name        AS `EmpName`
         , m.dept        AS `Department`
         , d.dt          AS `AbsentDate`
      FROM ( SELECT DATE(t.s_date) AS dt
               FROM emp_tx t
              WHERE t.s_date >= '2012-12-12' 
                AND t.s_date < DATE_ADD( '2012-12-20' ,INTERVAL 1 DAY)
              GROUP BY DATE(t.s_date)
              ORDER BY DATE(t.s_date)
           ) d
     CROSS
      JOIN master m
      LEFT
      JOIN emp_tx p
        ON p.s_date >= d.dt
       AND p.s_date <  d.dt + INTERVAL 1 DAY
       AND p.empcode = m.empcode
     WHERE p.empcode IS NULL
     ORDER
        BY m.empcode
         , d.dt
    

    その5番目の列を取得するTotalNoofAbsent 同じ結果セットで返される可能性はありますが、そのクエリは非常に面倒になります。この詳細は、返された結果セットを処理するときに、クライアント側でより効率的に処理される可能性があります。

    クエリの仕組み

    dとしてエイリアスされたインラインビュー チェックしている「日付」値のセットを取得します。 emp_txを使用する これらの「日付」値のソースとしてのテーブルは、これを行うための便利な方法です。 DATE()ではありません 関数は、DATETIME引数の「日付」部分のみを返します。 GROUP BYを使用しています 日付の明確なリストを取得します(つまり、重複する値はありません)。 (このインラインビュークエリで求めているのは、引数として渡された2つの値の間にある別個のDATE値のセットです。DATE値のリストを生成する他のより複雑な方法があります。)

    「不在」と見なすすべての「日付」値がテーブルのどこかに表示されている限り(つまり、少なくとも1つのempcode 関心のある各日付に1つのトランザクションがあり、emp_txの行数である限り テーブルが多すぎない場合は、インラインビュークエリが適切に機能します。

    (注:インラインビューのクエリを個別に実行して、結果が正しく、期待どおりであることを確認できます。)

    次のステップは、インラインビューから結果を取得し、CROSS JOINを実行することです。 すべてのempcodeに一致する操作(デカルト積を生成するため) すべてのdate インラインビューから返されます。この操作の結果は、「出席」のすべての可能な発生を表します。

    クエリの最後のステップは、LEFT JOINを使用して、「アンチジョイン」操作を実行することです。 およびWHERE IS NULL 述語。 LEFT JOIN (外部結合)は、emp_txからの一致する行(出席レコード)がないものを含め、(左側から)可能なすべての出席の発生を返します。 テーブル。

    「トリック」は、一致する出席レコードが見つかったすべての行を破棄する述語を(WHERE句に)含めることです。そのため、残っているのはempcodeのすべての組み合わせです。 およびdate (出席の可能性があります)一致する出席トランザクションがなかった場合。

    (注:述語にs_date(DATETIME)列 "bare"への参照を意図的に残し、範囲述語を使用しました。これにより、MySQLはその列を含む適切なインデックスを効果的に使用できるようになります。)

    >

    関数内の述語で列参照をラップする場合、たとえば、 DATE(p.s_date) 、その場合、MySQLはs_dateのインデックスを効果的に使用できなくなります 列。

    (あなたの質問に対する)コメントの1つが指摘しているように、従業員を「入ってきた」または「出て行った」とマークするトランザクションを区別していません。与えられた24時間の「真夜中から真夜中」の期間にそのempcodeのトランザクションの存在のみを探しています。

    同じ結果セットを取得する方法は他にもありますが、「反結合」パターンは通常、大きなセットで最高のパフォーマンスを発揮することがわかります。

    最高のパフォーマンスを得るには、インデックスをカバーすることをお勧めします:

    ... ON master (empcode, name, dept)
    
    ... ON emp_tx (s_date, empcode)
    


    1. mysqlテーブルにペルシア語のテキストを挿入します

    2. Laravel5.2の履歴テーブルの最新のエントリを取得するためのクエリ

    3. 同じテーブルに複数の行を挿入する方法-Oracle10g

    4. Oracle SQLクエリで角かっこはどういう意味ですか?