MyBatis練習:根據考勤記錄統計人員出勤狀況

個人電腦操做系統版本爲Win7旗艦版(ServicePack1),Oracle版本爲Oracle11gjava

程序使用的jar包有:mybatis-3.2.2.jar、ojdbc14-10.2.0.2.0.jarsql

本例中使用的配置文件mybatis-config.xml,能夠參見個人另外一篇Blog《一個簡單的MyBatis鏈接Oracle數據庫的例子》(http://my.oschina.net/Tsybius2014/blog/626206數據庫


本文仍是一個使用MyBatis進行查詢的練習之做。apache

現有三張表:session

1)OPERATOR表(簽到人員信息表)記錄了人員的ID和名稱,該表中每一個打卡人都做爲一條數據存入mybatis

2)WORKDAY表(工做日曆表)記錄了工做日曆,該表中每日都做爲一條數據存入,INFO_DATE列爲日期,IS_WORK_DAY列爲1時爲工做日,爲0時爲非工做日app

3)CLOCKING_IN_DATA表(打卡數據表)記錄了考勤打卡狀況,每次打卡向該表中插入一條數據,OPER_DATE爲打卡日期,OPER_TIME爲打卡時間,OPER_ID爲打卡人ID,OPER_NAME爲打卡人姓名測試

要求根據這三張表,計算出指定人的出勤狀況。ui

使用下面的SQL腳本,能夠向Oracle數據庫中插入基礎數據:spa

-- 簽到人員信息表
CREATE TABLE OPERATOR
(
    ID NUMBER(12, 0) PRIMARY KEY,
    OPER_ID VARCHAR(10),
    OPER_NAME VARCHAR(10)
);

INSERT INTO OPERATOR (ID, OPER_ID, OPER_NAME) VALUES (1, '0001', 'Tsybius');
INSERT INTO OPERATOR (ID, OPER_ID, OPER_NAME) VALUES (2, '0002', 'Galatea');

-- 工做日曆表
CREATE TABLE WORKDAY
(
    ID NUMBER(12, 0) PRIMARY KEY,
    INFO_DATE NUMBER(10, 0),
    IS_WORK_DAY CHAR
);

-- 2016年2月1-9日的工做日(1-五、八、9是工做日,六、7不是工做日)
INSERT INTO WORKDAY (ID, INFO_DATE, IS_WORK_DAY) VALUES (1, 20160201, '1');
INSERT INTO WORKDAY (ID, INFO_DATE, IS_WORK_DAY) VALUES (2, 20160202, '1');
INSERT INTO WORKDAY (ID, INFO_DATE, IS_WORK_DAY) VALUES (3, 20160203, '1');
INSERT INTO WORKDAY (ID, INFO_DATE, IS_WORK_DAY) VALUES (4, 20160204, '1');
INSERT INTO WORKDAY (ID, INFO_DATE, IS_WORK_DAY) VALUES (5, 20160205, '1');
INSERT INTO WORKDAY (ID, INFO_DATE, IS_WORK_DAY) VALUES (6, 20160206, '0');
INSERT INTO WORKDAY (ID, INFO_DATE, IS_WORK_DAY) VALUES (7, 20160207, '0');
INSERT INTO WORKDAY (ID, INFO_DATE, IS_WORK_DAY) VALUES (8, 20160208, '1');
INSERT INTO WORKDAY (ID, INFO_DATE, IS_WORK_DAY) VALUES (9, 20160209, '1');

-- 打卡數據表
CREATE TABLE CLOCKING_IN_DATA
(
    ID NUMBER(12, 0) PRIMARY KEY,
    OPER_DATE NUMBER(10, 0),
    OPER_TIME NUMBER(10, 0),
    OPER_ID VARCHAR(10),
    OPER_NAME VARCHAR(10)
);

-- Tsybius 的上下班數據 20160201-20160207
-- 正常上下班1 20160201
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (1, 20160201, 85531, '0001', 'Tsybius');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (2, 20160201, 180103, '0001', 'Tsybius');
-- 正常上下班2 20160202
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (3, 20160202, 85814, '0001', 'Tsybius');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (4, 20160202, 180809, '0001', 'Tsybius');
-- 遲到 20160203
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (5, 20160203, 90302, '0001', 'Tsybius');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (6, 20160203, 180809, '0001', 'Tsybius');
-- 早退 20160204
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (7, 20160204, 84513, '0001', 'Tsybius');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (8, 20160204, 155324, '0001', 'Tsybius');
-- 遲到 + 早退 20160205
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (9, 20160205, 103501, '0001', 'Tsybius');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (10, 20160205, 175000, '0001', 'Tsybius');
-- 曠工 - 只打了一次卡 20160208
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (11, 20160208, 83902, '0001', 'Tsybius');
-- 曠工 - 一次卡都沒打 20160209

-- Galatea 的上下班數據 20160201-20160207
-- 加班到晚上11點 20160201
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (12, 20160201, 85531, '0002', 'Galatea');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (13, 20160201, 235344, '0002', 'Galatea');
-- 加班到午夜12點,但12點前沒有打卡 20160202
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (14, 20160202, 85349, '0002', 'Galatea');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (15, 20160203, 3023, '0002', 'Galatea');
-- 正常上下班1 20160203
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (16, 20160203, 85958, '0002', 'Galatea');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (17, 20160203, 180004, '0002', 'Galatea');
-- 系統升級一早就要去看着 20160204
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (18, 20160204, 53824, '0002', 'Galatea');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (19, 20160204, 180213, '0002', 'Galatea');
-- 正常上下班2 20160205
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (20, 20160205, 84509, '0002', 'Galatea');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (21, 20160205, 180329, '0002', 'Galatea');
-- 正常上下班3 20160208
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (22, 20160208, 85944, '0002', 'Galatea');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (23, 20160208, 180114, '0002', 'Galatea');
-- 最後一天加班到半夜12點,12點前打了一次卡 20160209
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (24, 20160209, 84509, '0002', 'Galatea');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (25, 20160209, 235603, '0002', 'Galatea');
INSERT INTO CLOCKING_IN_DATA (ID, OPER_DATE, OPER_TIME, OPER_ID, OPER_NAME) VALUES (26, 20160210, 2003, '0002', 'Galatea');

COMMIT;
/

爲統計出指定人的考勤打卡狀況,我寫了一個SQL,用於查詢編號爲0001的人(Tsybius)的出勤記錄

統計規則以下:

一、一日的時間從當日0點起,至當日235959點止,每日統計最先的一次和最晚的一次打卡記錄

二、第一次打卡事件晚於9點鐘斷定爲遲到,最後一次打卡時間早於18點鐘算早退

三、一天打卡次數少於2次、很多於2次但2次都在12點前或12點後,按曠工計算

其中條件3在實際查詢中能夠轉換爲:不打卡按曠工計算,僅上午或僅下午有打卡記錄按曠工計算

查詢結果約定以下:0爲正常考勤,1爲遲到,2爲早退,3爲遲到+早退,4爲曠工

SELECT A.INFO_DATE,
       A.IS_WORK_DAY,
       C.OPER_ID,
       C.OPER_NAME,
       B.MIN_TIME,
       B.MAX_TIME,
       NVL(B.ATTENDANCE, 4) AS ATT_STATUS
FROM   (SELECT INFO_DATE, IS_WORK_DAY
        FROM   WORKDAY) A
        LEFT   JOIN (SELECT CI_DATA.*,
                            (CASE
                               WHEN CI_DATA.MIN_TIME < 90000 AND
                                    CI_DATA.MAX_TIME > 180000 THEN
                                '0'
                               ELSE
                                CASE
                               WHEN CI_DATA.MIN_TIME > 120000 OR
                                    CI_DATA.MAX_TIME < 120000 THEN
                                '4'
                               ELSE
                                CASE
                               WHEN CI_DATA.MIN_TIME > 90000 AND
                                    CI_DATA.MAX_TIME > 180000 THEN
                                '1'
                               ELSE
                                CASE
                               WHEN CI_DATA.MIN_TIME < 90000 AND
                                    CI_DATA.MAX_TIME < 180000 THEN
                                '2'
                               ELSE
                                '3'
                             END END END END) AS ATTENDANCE
             FROM   (SELECT OPER_DATE,
                            OPER_ID,
                            OPER_NAME,
                            MIN(OPER_TIME) AS MIN_TIME,
                            MAX(OPER_TIME) AS MAX_TIME
                     FROM   CLOCKING_IN_DATA
                     WHERE  OPER_ID = '0001'
                     GROUP  BY OPER_DATE, OPER_ID, OPER_NAME) CI_DATA) B 
        ON A.INFO_DATE = B.OPER_DATE,
        (SELECT OPER_ID, OPER_NAME
         FROM   OPERATOR
         WHERE  OPER_ID = '0001') C
ORDER  BY INFO_DATE

在PL/SQL中執行這個SQL語句,查詢出的結果集以下:

現使用MyBatis查詢這些數據,Java代碼以下:

import java.io.InputStream;
import java.text.MessageFormat;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

/**
 * MyBatis使用測試
 * @author Tsybius2014
 * @date 2016年3月20日
 * @time 下午5:40:55
 * @remark
 *
 */
public class MyBatisTest {
    
    public static void main(String[] args) {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession session = sqlSessionFactory.openSession();
            try {
                ClockingInMapper mapper = session.getMapper(ClockingInMapper.class);
                //按operId獲取考勤記錄
                printAttrStatus(mapper.selectAttStatusByOperId("0001"));
                printAttrStatus(mapper.selectAttStatusByOperId("0002"));
                
            } finally {
                session.close();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    /**
     * 輸出考勤記錄
     * @param attrStatusList 考勤記錄表
     */
    public static void printAttrStatus(List<Map<String, Object>> attrStatusList) {
        if (attrStatusList == null || attrStatusList.size() == 0) {
            return;
        }
        System.out.println("******** 考勤記錄 START ********");
        Iterator<Map<String, Object>> iter = attrStatusList.iterator();
        while (iter.hasNext()) {
            Map<String, Object> attrStatus = iter.next();
            String infoDate = attrStatus.get("infoDate").toString();
            String isWorkDay = attrStatus.get("isWorkDay").toString();
            String operId = attrStatus.get("operId").toString();
            String operName = attrStatus.get("operName").toString();
            String minTime = attrStatus.get("minTime") != null ? attrStatus.get("minTime").toString() : "";
            String maxTime = attrStatus.get("maxTime") != null ? attrStatus.get("maxTime").toString() : "";
            String attStatus = attrStatus.get("attStatus").toString();
            String attResult = "";
            if (isWorkDay.equals("0")) {
                attResult = "非工做日不考勤";
            } else if (isWorkDay.equals("1")) {
                if (attStatus.equals("0")) {
                    attResult = "考勤正常";
                } else if (attStatus.equals("1")) {
                    attResult = "遲到";
                } else if (attStatus.equals("2")) {
                    attResult = "早退";
                } else if (attStatus.equals("3")) {
                    attResult = "遲到,早退";
                } else if (attStatus.equals("4")) {
                    attResult = "曠工";
                } else {
                    attResult = "非法數據";
                }
            } else {
                attResult = "非法數據";
            }
            String result = MessageFormat.format(
                "日期: {0},人員:{1}({2}),考勤結果:{3},{4}-{5}", 
                infoDate, operName, operId, attResult, minTime, maxTime);
            System.out.println(result);
        }
        System.out.println("******** 考勤記錄 END ********");
    }
}

ClockingInMapper.java代碼以下:

import java.util.List;
import java.util.Map;

public interface ClockingInMapper {
    List<Map<String, Object>> selectAttStatusByOperId(String operId);
}

ClockingInMapper.xml代碼以下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ClockingInMapper">

    <resultMap id="AttendanceMap" type="java.util.Map" >
        <result column="INFO_DATE" property="infoDate" jdbcType="DECIMAL" />
        <result column="IS_WORK_DAY" property="isWorkDay" jdbcType="CHAR" />
        <result column="OPER_ID" property="operId" jdbcType="VARCHAR" />
        <result column="OPER_NAME" property="operName" jdbcType="VARCHAR" />
        <result column="MIN_TIME" property="minTime" jdbcType="DECIMAL" />
        <result column="MAX_TIME" property="maxTime" jdbcType="DECIMAL" />
        <result column="ATT_STATUS" property="attStatus" jdbcType="CHAR" />
    </resultMap>
    
    <select id="selectAttStatusByOperId" 
        parameterType="java.lang.String" resultMap="AttendanceMap" >
        SELECT A.INFO_DATE,
               A.IS_WORK_DAY,
               C.OPER_ID,
               C.OPER_NAME,
               B.MIN_TIME,
               B.MAX_TIME,
               NVL(B.ATTENDANCE, '4') AS ATT_STATUS
        FROM   (SELECT INFO_DATE, IS_WORK_DAY
                FROM   WORKDAY) A
                LEFT   JOIN (SELECT CI_DATA.*,
                                    (CASE
                                       WHEN CI_DATA.MIN_TIME <![CDATA[<]]> 90000 AND
                                            CI_DATA.MAX_TIME <![CDATA[>]]> 180000 THEN
                                        '0'
                                       ELSE
                                        CASE
                                       WHEN CI_DATA.MIN_TIME <![CDATA[>]]> 120000 OR
                                            CI_DATA.MAX_TIME <![CDATA[<]]> 120000 THEN
                                        '4'
                                       ELSE
                                        CASE
                                       WHEN CI_DATA.MIN_TIME <![CDATA[>]]> 90000 AND
                                            CI_DATA.MAX_TIME <![CDATA[>]]> 180000 THEN
                                        '1'
                                       ELSE
                                        CASE
                                       WHEN CI_DATA.MIN_TIME <![CDATA[<]]> 90000 AND
                                            CI_DATA.MAX_TIME <![CDATA[<]]> 180000 THEN
                                        '2'
                                       ELSE
                                        '3'
                                     END END END END) AS ATTENDANCE
                             FROM   (SELECT OPER_DATE,
                                            OPER_ID,
                                            OPER_NAME,
                                            MIN(OPER_TIME) AS MIN_TIME,
                                            MAX(OPER_TIME) AS MAX_TIME
                                     FROM   CLOCKING_IN_DATA
                                     WHERE  OPER_ID = #{operId, jdbcType = VARCHAR}
                                     GROUP  BY OPER_DATE, OPER_ID, OPER_NAME) CI_DATA) B 
                ON A.INFO_DATE = B.OPER_DATE,
                (SELECT OPER_ID, OPER_NAME
                 FROM   OPERATOR
                 WHERE  OPER_ID = #{operId, jdbcType = VARCHAR}) C
        ORDER  BY INFO_DATE
    </select>

</mapper>

這段Java代碼的運行結果以下:

******** 考勤記錄 START ********
日期: 20160201,人員:Tsybius(0001),考勤結果:考勤正常,85531-180103
日期: 20160202,人員:Tsybius(0001),考勤結果:考勤正常,85814-180809
日期: 20160203,人員:Tsybius(0001),考勤結果:遲到,90302-180809
日期: 20160204,人員:Tsybius(0001),考勤結果:早退,84513-155324
日期: 20160205,人員:Tsybius(0001),考勤結果:遲到,早退,103501-175000
日期: 20160206,人員:Tsybius(0001),考勤結果:非工做日不考勤,-
日期: 20160207,人員:Tsybius(0001),考勤結果:非工做日不考勤,-
日期: 20160208,人員:Tsybius(0001),考勤結果:曠工,83902-83902
日期: 20160209,人員:Tsybius(0001),考勤結果:曠工,-
******** 考勤記錄 END ********
******** 考勤記錄 START ********
日期: 20160201,人員:Galatea(0002),考勤結果:考勤正常,85531-235344
日期: 20160202,人員:Galatea(0002),考勤結果:曠工,85349-85349
日期: 20160203,人員:Galatea(0002),考勤結果:考勤正常,3023-180004
日期: 20160204,人員:Galatea(0002),考勤結果:考勤正常,53824-180213
日期: 20160205,人員:Galatea(0002),考勤結果:考勤正常,84509-180329
日期: 20160206,人員:Galatea(0002),考勤結果:非工做日不考勤,-
日期: 20160207,人員:Galatea(0002),考勤結果:非工做日不考勤,-
日期: 20160208,人員:Galatea(0002),考勤結果:考勤正常,85944-180114
日期: 20160209,人員:Galatea(0002),考勤結果:考勤正常,84509-235603
******** 考勤記錄 END ********

END

相關文章
相關標籤/搜索