从两个表中获取记录

时间:2011-12-30 07:01:27

标签: mysql

这是我的第一张表:指纹

 Serial UserID  Name            EmpID          CardID   Department     Designation       Status
   1    626242  HariharanJ      626242         626242   IT             Desktop Engineer  Active 
   2    626243  RomiltonA       626243         626243   IT             Desktop Engineer  Active

这是我的第二张表:tblemployeepunch

  fld_id    fld_date        fld_cardno  fld_mode    fld_punchdatetime
  1         29122011        626242      01          2011-12-29 13:01:00
  2         29122011        626243      01          2011-12-29 13:02:00
  3         29122011        626242      02          2011-12-29 13:30:00
  4         29122011        626243      02          2011-12-29 13:45:00

fld_mode 01表示intime 02表示停工时间 我需要以下输出:

 Employee_Id    Employee_Name   Department  Day         Punchdate   Intime      Outtime
 626242         HariharanJ      IT          Thursday    2011-12-29  13 : 01     13 : 30
 626243         RomiltonA       IT          Thursday    2011-12-29  13 : 02     13 : 45

请帮帮我

1 个答案:

答案 0 :(得分:2)

简单查询

让我们做一些简化的假设,样本数据满足:

  • 我们不必担心周二和周三出门的人;
  • 我们不必担心人们两次入住,一天两次退房;
  • 我们不必担心人们登录但不会退出;
  • 我们不必担心签名但不登录;
  • 由于UserID,EmpID和CardID对于这些用户中的每一个都具有相同的值,因此使用哪个用于与TblEmployeePunch表连接无关紧要。

通过这些假设,您可以像这样对查询进行编码:

SELECT e.userid                       AS Employee_ID,
       e.name                         AS Employee_Name,
       e.Department                   AS Department,
       DAYOFWEEK(i.fld_punchdatetime) AS Day,
       TIME(i.fld_punchdatetime)      AS InTime,
       TIME(o.fld_punchdatetime)      AS OutTime
  FROM Fingerprints     AS e
  JOIN TblEmployeePunch AS i
    ON e.userid = i.fld_cardno AND i.fld_mode = '01'
  JOIN TblEmployeePunch AS o
    ON e.userid = o.fld_cardno AND o.fld_mode = '02'
 WHERE i.fld_date = o.fld_date;

函数名称需要验证;假设DAYOFWEEK()将返回传递给定日期时间值的星期几的字符串。同样,TIME()函数将返回传入的日期时间值的时间组件。您可能需要指定一些额外的参数只能获得小时和分钟(而不是包括秒数)。


有些人登录但未注销,反之亦然

如果人们不小心(并且他们)是关于签名/打卡的,那么您有登录并且不签名的人,以及其他签名并且不登录的人。在评论中,我建议一个FULL OUTER JOIN可以解决这个问题;我不确定这是一个三通UNION的好主意。以下代码适用于IBM Informix Dynamic Server(IDS),并在带有IDS 11.70.FC2的MacOS X 10.7.2上进行了测试。

我分阶段开发了查询,这就是我总是处理这样的复杂查询的方式。

进出

SELECT i.Fld_CardNo        AS UserID,
       i.fld_punchdatetime AS i_time,
       o.fld_punchdatetime AS o_time
  FROM TblEmployeePunch AS i
  JOIN TblEmployeePunch AS o
    ON o.Fld_CardNo = i.Fld_CardNo AND i.Fld_Date = o.Fld_Date
 WHERE i.fld_mode = '01' AND o.fld_mode = '02';

结果

 userid     i_time  o_time
 626242     2011-12-29 13:01:00     2011-12-29 13:30:00
 626243     2011-12-29 13:02:00     2011-12-29 13:45:00

仅限

SELECT i.Fld_Cardno        AS UserID,
       i.Fld_PunchDateTime AS i_time,
       CAST(NULL AS DATETIME YEAR TO SECOND) AS o_time
  FROM TblEmployeePunch AS i
 WHERE NOT EXISTS
       (SELECT *
          FROM TblEmployeePunch AS o
         WHERE o.Fld_Cardno = i.Fld_Cardno
           AND o.Fld_Date   = i.Fld_Date
           AND o.Fld_Mode   = '02'
       )
   AND i.fld_mode = '01';

结果

 userid     i_time                  o_time
 626247     2011-12-29 10:15:00              

仅限

SELECT o.Fld_Cardno        AS UserID,
       CAST(NULL AS DATETIME YEAR TO SECOND) AS i_time,
       o.Fld_PunchDateTime AS o_time
  FROM TblEmployeePunch AS o
 WHERE NOT EXISTS
       (SELECT *
          FROM TblEmployeePunch AS i
         WHERE i.Fld_Cardno = o.Fld_Cardno
           AND i.Fld_Date   = o.Fld_Date
           AND i.Fld_Mode   = '01'
       )
   AND o.fld_mode = '02';

结果

 userid     i_time                  o_time
 626248                             2011-12-29 11:05:00

3-way UNION for'in and out','only only'和'out only'

SELECT i.Fld_CardNo        AS UserID,
       i.fld_punchdatetime AS i_time,
       o.fld_punchdatetime AS o_time
  FROM TblEmployeePunch AS i
  JOIN TblEmployeePunch AS o
    ON o.Fld_CardNo = i.Fld_CardNo AND i.Fld_Date = o.Fld_Date
 WHERE i.fld_mode = '01' AND o.fld_mode = '02'
UNION
SELECT i.Fld_Cardno        AS UserID,
       i.Fld_PunchDateTime AS i_time,
       CAST(NULL AS DATETIME YEAR TO SECOND) AS o_time
  FROM TblEmployeePunch AS i
 WHERE NOT EXISTS
       (SELECT *
          FROM TblEmployeePunch AS o
         WHERE o.Fld_Cardno = i.Fld_Cardno
           AND o.Fld_Date   = i.Fld_Date
           AND o.Fld_Mode   = '02'
       )
   AND i.fld_mode = '01'
UNION
SELECT o.Fld_Cardno        AS UserID,
       CAST(NULL AS DATETIME YEAR TO SECOND) AS i_time,
       o.Fld_PunchDateTime AS o_time
  FROM TblEmployeePunch AS o
 WHERE NOT EXISTS
       (SELECT *
          FROM TblEmployeePunch AS i
         WHERE i.Fld_Cardno = o.Fld_Cardno
           AND i.Fld_Date   = o.Fld_Date
           AND i.Fld_Mode   = '01'
       )
   AND o.fld_mode = '02';

结果

 userid     i_time  o_time
 626242     2011-12-29 13:01:00     2011-12-29 13:30:00
 626243     2011-12-29 13:02:00     2011-12-29 13:45:00
 626247     2011-12-29 10:15:00                   
 626248                             2011-12-29 11:05:00

最终查询

将3路UNION与指纹表连接起来产生:

SELECT e.userid            AS Employee_ID,
       e.name              AS Employee_Name,
       e.Department        AS Department,
       DAYOFWEEK(t.i_time) AS Day,
       TIME(t.i_time)      AS InTime,
       TIME(t.o_time)      AS OutTime
  FROM Fingerprints AS e
  JOIN (SELECT i.Fld_CardNo        AS UserID,
               i.fld_punchdatetime AS i_time,
               o.fld_punchdatetime AS o_time
          FROM TblEmployeePunch AS i
          JOIN TblEmployeePunch AS o
            ON o.Fld_CardNo = i.Fld_CardNo AND i.Fld_Date = o.Fld_Date
         WHERE i.fld_mode = '01' AND o.fld_mode = '02'
        UNION
        SELECT i.Fld_Cardno        AS UserID,
               i.Fld_PunchDateTime AS i_time,
               CAST(NULL AS DATETIME YEAR TO SECOND) AS o_time
          FROM TblEmployeePunch AS i
         WHERE NOT EXISTS
               (SELECT *
                  FROM TblEmployeePunch AS o
                 WHERE o.Fld_Cardno = i.Fld_Cardno
                   AND o.Fld_Date   = i.Fld_Date
                   AND o.Fld_Mode   = '02'
               )
           AND i.fld_mode = '01'
        UNION
        SELECT o.Fld_Cardno        AS UserID,
               CAST(NULL AS DATETIME YEAR TO SECOND) AS i_time,
               o.Fld_PunchDateTime AS o_time
          FROM TblEmployeePunch AS o
         WHERE NOT EXISTS
               (SELECT *
                  FROM TblEmployeePunch AS i
                 WHERE i.Fld_Cardno = o.Fld_Cardno
                   AND i.Fld_Date   = o.Fld_Date
                   AND i.Fld_Mode   = '01'
               )
           AND o.fld_mode = '02'
       ) AS t
    ON e.userid = t.userid
 ORDER BY e.userid;

最终数据

 employee_id   employee_name   department   day        intime     outtime
 626242        HariharanJ      IT           Thursday   13:01:00   13:30:00
 626243        RomiltonA       IT           Thursday   13:02:00   13:45:00
 626247        InnerJ          IS           Thursday   10:15:00        
 626248        OuterJ          IS                                 11:05:00

哦,小提琴:当intime为空时,星期几出现空。这可以修复;我将它作为练习留给读者。 (提示:COALESCE()或NVL()或者IFNULL()可能会在答案中找到答案。)


支持信息

指纹表和数据

CREATE TABLE Fingerprints
(
    Serial      SERIAL NOT NULL PRIMARY KEY,
    UserID      INTEGER NOT NULL UNIQUE,
    Name        CHAR(15) NOT NULL,
    EmpID       INTEGER NOT NULL UNIQUE,
    CardID      INTEGER NOT NULL UNIQUE,
    Department  CHAR(10) NOT NULL,
    Designation CHAR(20) NOT NULL,
    Status      CHAR(8) NOT NULL CHECK(Status IN ('Active', 'Inactive'))
);

INSERT INTO Fingerprints VALUES(1, 626242, "HariharanJ", 626242, 626242, "IT", "Desktop Engineer", "Active");
INSERT INTO Fingerprints VALUES(2, 626243, "RomiltonA",  626243, 626243, "IT", "Desktop Engineer", "Active");
INSERT INTO Fingerprints VALUES(3, 626247, "InnerJ",     626247, 626247, "IS", "Web Technician",   "Active");
INSERT INTO Fingerprints VALUES(4, 626248, "OuterJ",     626248, 626248, "IS", "Web Technician",   "Active");

TblEmployeePunch表和数据

CREATE TABLE TblEmployeePunch
(
    Fld_ID              SERIAL NOT NULL PRIMARY KEY,
    Fld_Date            INTEGER NOT NULL,
    Fld_CardNo          INTEGER NOT NULL REFERENCES Fingerprints(UserID),
    Fld_Mode            CHAR(2) NOT NULL,
    Fld_PunchDateTime   DATETIME YEAR TO SECOND NOT NULL
);

INSERT INTO TblEmployeePunch VALUES(1, 29122011, 626242, "01", "2011-12-29 13:01:00");
INSERT INTO TblEmployeePunch VALUES(2, 29122011, 626243, "01", "2011-12-29 13:02:00");
INSERT INTO TblEmployeePunch VALUES(3, 29122011, 626242, "02", "2011-12-29 13:30:00");
INSERT INTO TblEmployeePunch VALUES(4, 29122011, 626243, "02", "2011-12-29 13:45:00");
INSERT INTO TblEmployeePunch VALUES(5, 29122011, 626247, "01", "2011-12-29 10:15:00");
INSERT INTO TblEmployeePunch VALUES(6, 29122011, 626248, "02", "2011-12-29 11:05:00");

DayOfWeek功能

Informix不提供国际化的DAYOFWEEK功能,因此这里有替代品(也没有国际化)。可能使用TO_DATE()和适当的格式字符串来编写国际化版本。

CREATE PROCEDURE DayOfWeek(d DATE) RETURNING CHAR(9);
    DEFINE dow INTEGER;
    LET dow = WEEKDAY(d);
    IF dow = 0 THEN RETURN "Sunday";    END IF;
    IF dow = 1 THEN RETURN "Monday";    END IF;
    IF dow = 2 THEN RETURN "Tuesday";   END IF;
    IF dow = 3 THEN RETURN "Wednesday"; END IF;
    IF dow = 4 THEN RETURN "Thursday";  END IF;
    IF dow = 5 THEN RETURN "Friday";    END IF;
    IF dow = 6 THEN RETURN "Saturday";  END IF;
    RETURN NULL;
END PROCEDURE;

TIME

Informix使用一组类型,例如DATETIME YEAR TO SECOND而不是TIMESTAMP和DATETIME HOUR TO SECOND而不是TIME。此函数将'TIMESTAMP'转换为'TIME'。

CREATE PROCEDURE Time(dt DATETIME YEAR TO SECOND) RETURNING DATETIME HOUR TO SECOND;
    RETURN EXTEND(dt, HOUR TO SECOND);
END PROCEDURE;