在MySql中的滑动时间窗口内运行每个id的总数

时间:2013-06-30 22:44:33

标签: mysql sql

我需要一个查询,可以告诉我昨天,前2天和前3天给定idTest的idObj数。

前2天标记的idObj数量应包括idObj标记昨天,即它应该只显示昨天和之前2天标记的idObj的数量。 标记为3天前的idOjb数量应包括标记为昨天,前2天和前3天的idObj。

我还需要列的名称作为日期而不是'DayBeforeYest'和'TwoDayBefore'。

以下是我要找的内容:

idTest    2013-06-29    2013-06-28    2013-06-27
104        9              7                 5
105        7              6             2
106        5              3             0

此处,在2013-06-29,idObj计数包括仅在2013-06-29标记的idObj。在2013-06-28,idObj计数包括已在2013-06-29和2013-06-28标记的idObj。在2013-06-27,idObj计数包括已标记的idObj 2013-06-29,2013-06-06和2013-06-27。因此,与昨天相比,3天前列的idObj计数会更少。

查询

create table tblTest (dateFact date, idTest int, idObj int);

insert into tblTest values
('2013-06-29', 104, 4433), ('2013-06-29', 105, 3345), ('2013-06-29', 106, 5543),
('2013-06-28', 104, 4433), ('2013-06-28', 105, 3345), ('2013-06-28', 106, 4356),
('2013-06-27', 104, 3439), ('2013-06-07', 105, 3345), ('2013-06-07', 106, 8955);

以下是我提出的查询,但它只计算每个idTest在第2天和第3天标记的idObj的数量。它没有考虑在流行天数中标记的idObj。它也不以日期格式显示列名。

select idTest, max(Yest) as Yest, max(DayBeforeYest) as DayBeforeYest,     max(TwoDayBefore) as TwoDayBefore from
(
(select idTest, count(idObj) as Yest, 0 as DayBeforeYest, 0 as TwoDayBefore from tblTest
where dateFact =date_sub(curdate(), interval 1 day) group by idTest)
union
(select idTest, 0 as Yest, count(idObj) DayBeforeYest, 0 as TwoDayBefore from tblTest
where dateFact = date_Sub(curdate(), interval 2 day) group by idTest)
union
(select idTest, 0 as Yest, 0 as DayBeforeYest , count(idObj) TwoDayBefore from tblTest
where dateFact = date_sub(curdate(), interval 3 day) group by idTest) )x
group by idTest;

谢谢!

====================================

编辑:

create table tblTest (dateFact date, idTest int, idObj int);

INSERT INTO tblTest
select CURDATE() - INTERVAL 1 DAY, 104, 4433 UNION ALL
SELECT CURDATE() - INTERVAL 1 DAY, 105, 3345 UNION ALL
SELECT CURDATE() - INTERVAL 1 DAY, 106, 5543 UNION ALL
SELECT CURDATE() - INTERVAL 2 DAY, 104, 4433 UNION ALL
SELECT CURDATE() - INTERVAL 2 DAY, 105, 3345 UNION ALL
SELECT CURDATE() - INTERVAL 2 DAY, 106, 4356 UNION ALL
SELECT CURDATE() - INTERVAL 3 DAY, 104, 3439 UNION ALL
SELECT CURDATE() - INTERVAL 3 DAY, 105, 3345 UNION ALL
SELECT CURDATE() - INTERVAL 3 DAY, 106, 8955;

对于给定的示例,输出应如下所示:

idTest    2013-06-30    2013-06-29    2013-06-28
104         1           1                0
105         1           1                1
106         1           0                0

在2013-06-30为idTest 104,我们有1个idObj 4433.在2013-06-29为idTest 104,我们有1个idObj 4433,这也是2013-06-30的idTest 104。 在2013-06-28对于idTest 104,我们有1个idObj 3439,它不在2013-06-30或2013-06-29中用于idTest 104.因此,您将看到104的行值为1 1 0。 / p>

在2013-06-30为idTest 105,我们有1个idObj 3345.在2013-06-29为idTest 105,我们有1个idObj 3345,这也是2013-06-30 idTest 105。 在2013-06-28 for idTest 105,我们有1个idObj 3345,也是2013-06-30和2013-06-29。因此,您将看到行值为1 1 1。

等等......

在2013-06-28,计算idObj,它应该出现在2013-06-28,213-06-29,2013-06-30。 在2013-06-29,计算idObj,它应该出现在2013-06-29和2013-06-30。 在2013-06-30,计算idObj,它应该出现在2013-06-30。

1 个答案:

答案 0 :(得分:0)

更新要使列名成为日期,您必须使用动态SQL。

SET @sql = CONCAT(
'SELECT  idTest 
       , SUM(d1) `', DATE_FORMAT(CURDATE() - INTERVAL 1 DAY, '%Y-%m-%d'), 
       '`, SUM(d2 = 1 AND d1 = 1) `', DATE_FORMAT(CURDATE() - INTERVAL 2 DAY, '%Y-%m-%d'),
       '`, SUM(d3 = 1 AND d2 = 1 AND d1 = 1) `', DATE_FORMAT(CURDATE() - INTERVAL 3 DAY, '%Y-%m-%d'),
'`  FROM
(
  SELECT  idTest
         ,idObj
         ,SUM(CASE WHEN dateFact = CURDATE() - INTERVAL 1 DAY THEN 1 ELSE 0 END) d1
         ,SUM(CASE WHEN dateFact = CURDATE() - INTERVAL 2 DAY THEN 1 ELSE 0 END) d2
         ,SUM(CASE WHEN dateFact = CURDATE() - INTERVAL 3 DAY THEN 1 ELSE 0 END) d3
    FROM tblTest
   WHERE dateFact BETWEEN CURDATE() - INTERVAL 3 DAY AND CURDATE() - INTERVAL 1 DAY
   GROUP BY idTest, idObj
) q
 GROUP BY idTest');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

示例输出:

| IDTEST | 2013-07-02 | 2013-07-01 | 2013-06-30 |
-------------------------------------------------
|    104 |          1 |          1 |          0 |
|    105 |          1 |          1 |          1 |
|    106 |          1 |          0 |          0 |

这是 SQLFiddle 演示

为了让客户端(调用)方面的生活更轻松,您可以将此代码包装到存储过程中

DELIMITER $$
CREATE PROCEDURE sp_test_report()
BEGIN
  -- put above mentioned code here
END$$
DELIMITER ;

然后使用它

CALL sp_test_report();

这是 SQLFiddle 演示