查询期间的空值

时间:2013-12-30 20:37:45

标签: mysql sql select stored-procedures join

我有下表,非常简单。

==========================================================================
attendanceID   |   agentID   |   incurredDate   |   points   |   comment
==========================================================================
    10         |  vimunson   |    2013-07-22    |     2      | Some Text
    11         |  vimunson   |    2013-07-29    |     2      | Some Text
    12         |  vimunson   |    2013-12-06    |     1      | Some Text

他的查询如下:

SELECT 
    attendanceID,
    agentID,
    incurredDate,
    leadDate,
    points,
    @1F:=IF(incurredDate <= curdate() - 90
            AND leadDate = NULL,
        points - 1,
        IF(DATEDIFF(leadDate, incurredDate) > 90,
            points - 1,
            points)) AS '1stFallOff',
    @2F:=IF(incurredDate <= curdate() - 180
            AND leadDate = NULL,
        points - 2,
        IF(DATEDIFF(leadDate, incurredDate) > 180,
            points - 2,
            @1F)) AS '2ndFallOff',
    IF(@total < 0, 0, @total:=@total + @2F) AS Total,
    comment,
    linked
FROM
    (SELECT 
        attendanceID,
            mo.agentID,
            @r AS leadDate,
            (@r:=incurredDate) AS incurredDate,
            comment,
            points,
            linked
    FROM
        (SELECT 
        m . *
    FROM
        (SELECT @_date = NULL, @total:=0) varaible, attendance m
    ORDER by agentID , incurredDate desc) mo
    where
        agentID = 'vimunson'
            AND (case
            WHEN @_date is NULL or @_date <> incurredDate THEN @r:=NULL
            ELSE NULL
        END IS NULL)
            AND (@_date:=incurredDate) IS NOT NULL) T
ORDER BY agentID , incurredDate

当我运行查询时,它返回以下内容:

========================================================================================================================================
attendanceID   |   agentID   |   incurredDate   |   leadDate   |   points   |   1stFallOff   |   2ndFallOff   |   Total   |   comment
========================================================================================================================================
   10          |  vimunson   |   2013-07-22     |     NULL     |     2      |       2        |       2        |     2     |   Some Text
   11          |  vimunson   |   2013-07-29     |     NULL     |     2      |       2        |       2        |     4     |   Some Text
   12          |  vimunson   |   2013-12-06     |     NULL     |     1      |       2        |       1        |     5     |   Some Text

我无法弄清楚为什么leadDate列是'null&#39;。我已将其缩小到用户会话。例如,如果我使用相同的用户会话再次运行它,它将返回我想要的。

3 个答案:

答案 0 :(得分:1)

传递变量@r@_date的方式依赖于查询某些部分的特定顺序。这是一种冒险的假设,在查询语言中使用声明而非命令。查询优化器越复杂,此查询的行为就越不可预测。 “简单”引擎可能会遵循您的意图,另一个引擎可能会调整其行为,例如,因为它使用临时索引来提高查询性能。

在需要将值从一行传递到另一行的情况下,最好使用游标。 http://dev.mysql.com/doc/refman/5.0/en/cursors.html

编辑:以下示例代码。

我专注于专栏'leadDate';衰减和总列的实现应该是相似的。

CREATE PROCEDURE MyProc()
BEGIN
    DECLARE done int DEFAULT FALSE;
    DECLARE currentAttendanceID int;
    DECLARE currentAgentID, previousAgentID varchar(8);
    DECLARE currentIncurredDate date;
    DECLARE currentLeadDate date;
    DECLARE currentPoints int;
    DECLARE currentComment varchar(9);
    DECLARE myCursor CURSOR FOR
        SELECT attendanceID, agentID, incurredDate, points, comment
        FROM attendance
        ORDER BY agentID, incurredDate DESC;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    CREATE TEMPORARY TABLE myTemp (
        attendanceID int,
        agentID varchar(8),
        incurredDate date,
        leadDate date,
        points int,
        comment varchar(9)
    ) ENGINE=MEMORY;

    OPEN myCursor;

    SET previousAgentID := NULL;

    read_loop: LOOP
        FETCH myCursor INTO currentAttendanceID, currentAgentID, currentIncurredDate, currentPoints, currentComment;
        IF done THEN
            LEAVE read_loop;
        END IF;
        IF previousAgentID IS NULL OR previousAgentID <> currentAgentID THEN
            SET currentLeadDate := NULL;
            SET previousAgentID := currentAgentID;
        END IF;
        INSERT INTO myTemp VALUES (currentAttendanceID, currentAgentID, currentIncurredDate, currentLeadDate, currentPoints, currentComment);
        SET currentLeadDate := currentIncurredDate;
    END LOOP;

    CLOSE myCursor;

    SELECT *
    FROM myTemp
    ORDER BY agentID, incurredDate;

    DROP TABLE myTemp;
END

FYC:http://sqlfiddle.com/#!2/910a3/1/0

答案 1 :(得分:0)

试试这个:

SELECT a.attendanceID, a.agentID, a.incurredDate, a.leadDate, a.points, 
       @1F:= (CASE WHEN incurredDate <= CURDATE()-90 AND leadDate=NULL THEN points-1 
                   WHEN DATEDIFF(leadDate, incurredDate) > 90 THEN points-1 
                   ELSE points 
              END) AS '1stFallOff',
       @2F:= (CASE WHEN incurredDate <= CURDATE()-180 AND leadDate=NULL THEN points-2 
                   WHEN DATEDIFF(leadDate, incurredDate) > 180 THEN points-2 
                   ELSE @1F 
              END) AS '2ndFallOff',
     (@Total:=@Total + a.points) AS Total, a.comment 
FROM (SELECT a.attendanceID, a.agentID, a.incurredDate, b.incurredDate leadDate, a.points, a.comment 
      FROM attendance a 
      LEFT JOIN attendance b ON a.agentID = b.agentID AND a.incurredDate < b.incurredDate 
      GROUP BY a.agentID, a.incurredDate
     ) AS A, (SELECT @Total:=0, @1F:=0, @2F:=0) B;

检查SQL FIDDLE DEMO

<强>输出

| ATTENDANCEID |  AGENTID |                    INCURREDDATE |                        LEADDATE | POINTS | 1STFALLOFF | 2NDFALLOFF | TOTAL |   COMMENT |
|--------------|----------|---------------------------------|---------------------------------|--------|------------|------------|-------|-----------|
|           10 | vimunson |     July, 22 2013 00:00:00+0000 |     July, 29 2013 00:00:00+0000 |      2 |          2 |          2 |     2 | Some Text |
|           11 | vimunson |     July, 29 2013 00:00:00+0000 | December, 06 2013 00:00:00+0000 |      2 |          1 |          1 |     4 | Some Text |
|           12 | vimunson | December, 06 2013 00:00:00+0000 |                          (null) |      1 |          1 |          1 |     5 | Some Text |

答案 2 :(得分:0)

在审核了多个结果后,我能够提出一些我期望的东西。我输入了更多数据和以下语法。我喜欢光标的想法,但它不适合我使用,所以我没有使用它。我不想使用CASE或任何JOINS因为它们可能很复杂。

http://sqlfiddle.com/#!2/2fb86/1

SELECT 
    attendanceID,
    agentID,
    incurredDate,
    @ld:=(select 
            incurredDate
        from
            attendance
        where
            incurredDate > a.incurredDate
                and agentID = a.agentID
        order by incurredDate
        limit 1) leadDate,
    points,
    @1F:=IF(incurredDate <= DATE_SUB(curdate(),
            INTERVAL IF(incurredDate < '2013-12-02', 90, 60) DAY)
            AND @ld <=> NULL,
        points - 1,
        IF(DATEDIFF(COALESCE(@ld, '1900-01-01'),
                    incurredDate) > IF(incurredDate < '2013-12-02', 90, 60),
            points - 1,
            points)) AS '1stFallOff',
    @2F:=IF(incurredDate <= DATE_SUB(curdate(),
            INTERVAL IF(incurredDate < '2013-12-02',
                180,
                120) DAY)
            AND getLeadDate(incurredDate, agentID) <=> NULL,
        points - 1,
        IF(DATEDIFF(COALESCE(@ld, '1900-01-01'),
                    incurredDate) > IF(incurredDate < '2013-12-02',
                180,
                120),
            points - 2,
            @1F)) AS '2ndFallOff',
    IF((@total + @2F) < 0,
        0,
        IF(DATE_ADD(incurredDate, INTERVAL 365 DAY) <= CURDATE(),
            @total:=0,
            @total:=@total + @2F)) AS Total,
    comment,
    linked,
    DATE_ADD(incurredDate, INTERVAL 365 DAY) AS 'fallOffDate'
FROM
    (SELECT @total:=0) v,
    attendance a
WHERE
    agentID = 'vimunson'
GROUP BY agentID , incurredDate