使用带有状态检查的3个表的棘手SQL语句

时间:2012-04-28 20:26:17

标签: mysql sql

也许有人可以对我一整天都在努力的声明有所了解:)

我有3张桌子

度假

holidayID | userID | dateFrom   | dateTo
1         |      1 | 2012-01-01 | 2012-01-01
2         |      1 | 2012-01-15 | 2012-01-20

状态

statusID | holidayID | statusText
1        |         1 | accepted
2        |         2 | declined

UserSettings

id | userID | HolidaysAllowed
1  |      1 | 20

我要做的是获得以下结果

结果

HolidaysAllowed | HolidaysLeft (Allowed - Taken) | HolidaysTaken (Sum of Holidays)
20              |                             19 |      1

如果我没有说明状态,我可以获得所有三列 - 这是我最接近的

SELECT 
IFNULL(SUM( IF(  h.dateTo = h.dateFrom, 1, DATEDIFF( h.dateTo, h.dateFrom ) ) ), 0) AS holidaysTaken, 
IFNULL(us.HolidaysAllowed - ( SUM(  IF(  h.DateTo = h.DateFrom, 1, DATEDIFF( h.DateTo, h.dateFrom ) ) ) ), 0) AS holidaysLeftover, 
us.HolidaysAllowed
FROM userSettings us 
LEFT JOIN holiday h 
ON h.userID = 1 
JOIN status s 
ON s.holidayID = h.holidayID AND s.statusID = 1 
WHERE 
us.userID = 1
GROUP BY h.userID;

主要问题是,如果没有statusID = 2的假期,那么结果列1& 2是0(这是正确的)但第3列(HolidaysAllowed)是NULL(不正确,因为它需要始终从表UserSettings返回值)。上述查询仅在至少有1个记录(假日)状态正确时才返回正确的响应...我做错了什么? :)

它只是让我疯了:)在此先感谢任何帮助!非常感谢!

更新

感谢所有评论的人......预期结果如下 获取状态= 1(即已接受)的所有假期,然后根据允许的假期计算假期统计数据。即。

总共20天,接受1个假期=剩余19天

再次感谢

3 个答案:

答案 0 :(得分:3)

SELECT u.userID, u.HolidaysAllowed,
u.holidaysAllowed - 
COALESCE( 
    (SELECT SUM( DATEDIFF( h1.dateTo, h1.dateFrom) + 1) 
         FROM holiday h1 
         INNER JOIN status s1
         ON s1.holidayID = h1.holidayID
         WHERE h1.userID = u.userID
         AND s1.statusID = 1
     ), 0) AS HolidaysLeft,
COALESCE( 
    (SELECT SUM( DATEDIFF( h2.dateTo, h2.dateFrom) + 1) 
         FROM holiday h2 
         INNER JOIN status s2
         ON s2.holidayID = h2.holidayID
         WHERE h2.userID = u.userID
         AND s2.statusID = 1
     ), 0) AS HolidaysTaken
FROM userSettings u
;

答案 1 :(得分:2)

以下查询不会考虑周末。

Click here to view the demo in SQL Fiddle.

脚本

CREATE TABLE Holiday 
(       
        holidayid   INT         NOT NULL AUTO_INCREMENT
    ,   userid      VARCHAR(20) NOT NULL 
    ,   dateFrom    DATETIME    NOT NULL 
    ,   dateTo      DATETIME    NOT NULL 
    ,   PRIMARY KEY(holidayid)
);

CREATE TABLE Status
(       
        id          INT         NOT NULL AUTO_INCREMENT
    ,   holidayid   INT         NOT NULL
    ,   statusid    INT         NOT NULL
    ,   PRIMARY KEY(id)
);

CREATE TABLE UserSettings
(       
        id              INT     NOT NULL AUTO_INCREMENT
    ,   userid          INT     NOT NULL
    ,   HolidaysAllowed INT     NOT NULL
    ,   PRIMARY KEY(id)
);

INSERT INTO  Holiday (userid, dateFrom, dateTo) VALUES
    (1, '2012-04-01', '2012-04-03'),
    (2, '2012-04-04', '2012-04-05'),
    (2, '2012-04-07', '2012-04-09'),
    (3, '2012-04-09', '2012-04-12'),
    (3, '2012-04-16', '2012-04-16'),
    (1, '2012-04-19', '2012-04-22');

INSERT INTO  Status (holidayid, statusid) VALUES
    (1, 2),
    (2, 1),
    (3, 1),
    (4, 1),
    (5, 2),
    (6, 2);

INSERT INTO  UserSettings (userid, HolidaysAllowed) VALUES
    (1, 5),
    (2, 10),
    (3, 7),
    (4, 6);


SELECT  u.userid
    ,   u.HolidaysAllowed
    ,   u.HolidaysAllowed - COALESCE(hol.HolidaysTaken, 0) AS HolidaysLeft
    ,   COALESCE(hol.HolidaysTaken, 0) AS HolidaysTaken
FROM
(
    SELECT          h.userid
                ,   ABS(SUM(
                      CASE 
                        WHEN statusid = 1 THEN DATEDIFF(dateTo, dateFrom) + 1
                        ELSE 0 END
                    )) HolidaysTaken

    FROM            UserSettings    us
    LEFT OUTER JOIN Holiday         h
    ON              us.userid       = h.userid
    LEFT OUTER JOIN Status          s
    ON              s.holidayid     = h.holidayid
    GROUP BY        h.userid
)                   hol
RIGHT OUTER JOIN    UserSettings u
ON                  u.userid = hol.userid;

输出

USERID HOLIDAYSALLOWED HOLIDAYSLEFT HOLIDAYSTAKEN
------ --------------- ------------ -------------
1             5              5            0
2            10              5            5
3             7              3            4
4             6              6            0

答案 2 :(得分:0)

SELECT B.HolidaysAllowed AS HolidaysAllowed,
       B.HolidaysAllowed-A.HolidaysTaken AS HolidaysLeft,
       A.HolidaysTaken AS HolidaysTaken
FROM
(
 SELECT A.userID,SUM(CASE WHEN DATEDIFF(A.dateTo,A.dateFom)=0
                          THEN 1
                          ELSE DATEDIFF(A.dateTo,A.dateFom)
                    ) AS HolidaysTaken
 FROM Holiday A,Status B
 WHERE A.holidayID = B.holidayID
   AND A.statusText='accepted'
 GROUP BY useID
) A,
UserSettings B
WHERE A.userID = B.userID;