如何通过每周的成绩来改善我的SQL声明,并在周四或一周的其他任何一天开始一周?

dba.stackexchange https://dba.stackexchange.com/questions/6045

  •  16-10-2019
  •  | 
  •  

我是一个全新的B,我找不到任何在任何地方做到这一点的好方法。我有一个数据库表,其中包含在整个星期的不同时间记录的统计数据。报告周从星期四开始。该表包含记录数据时存储的Datestamp列(日期)。

我需要在给定的一周内提取数据(报告周从星期四开始)。我写了以下查询:

   SELECT * 
FROM `table` 
WHERE 1 = CASE 
  WHEN WEEKDAY(NOW()) = 0 THEN DATEDIFF(NOW(),`date`) BETWEEN -2 AND 4
  WHEN WEEKDAY(NOW()) = 1 THEN DATEDIFF(NOW(),`date`) BETWEEN -1 AND 5
  WHEN WEEKDAY(NOW()) = 2 THEN DATEDIFF(NOW(),`date`) BETWEEN -0 AND 6
  WHEN WEEKDAY(NOW()) = 3 THEN DATEDIFF(NOW(),`date`) BETWEEN -6 AND 0
  WHEN WEEKDAY(NOW()) = 4 THEN DATEDIFF(NOW(),`date`) BETWEEN -5 AND 1
  WHEN WEEKDAY(NOW()) = 5 THEN DATEDIFF(NOW(),`date`) BETWEEN -4 AND 2
  WHEN WEEKDAY(NOW()) = 6 THEN DATEDIFF(NOW(),`date`) BETWEEN -3 AND 3
END

这似乎在初始测试中起作用。但是我不确定这是最好的方法。我对MySQL的性能了解不多,但是要过滤的记录将有十万多个记录。由于检查的条件数量,此查询会真正缓慢吗?

在提取最新报告时,使用现在的()函数 - 但是,某些情况我需要在其他几周内进行报告,因此我将替换另一个日期到达该地点。

另外,这样做需要重新编写查询,如果报告周发生变化 - 说开始日的起点变为星期三。

我不能使用teek()函数,因为您只能在Sun或Mon上开始一周。

不胜感激的是改进此查询的任何想法!

其他注释:目前使用Mariadb 5.3。

有帮助吗?

解决方案

这是我写的一个查询,可以给您最近的星期四和周三结束

SELECT thuwk_beg + INTERVAL 0 second thu_beg,
thuwk_beg + INTERVAL 604799 second wed_end
FROM (SELECT (DATE(NOW()) - INTERVAL daysbacktothursday DAY) thuwk_beg
FROM (SELECT SUBSTR('3456012',wkndx,1) daysbacktothursday
FROM (SELECT DAYOFWEEK(dt) wkndx FROM (SELECT DATE(NOW()) dt) AAAA) AAA) AA) A;

这是今天,2011-09-21的示例

mysql> SELECT
    -> thuwk_beg + INTERVAL 0 second thu_beg,
    -> thuwk_beg + INTERVAL 604799 second wed_end
    -> FROM (SELECT (DATE(NOW()) - INTERVAL daysbacktothursday DAY) thuwk_beg
    -> FROM (SELECT SUBSTR('3456012',wkndx,1) daysbacktothursday
    -> FROM (SELECT DAYOFWEEK(dt) wkndx FROM (SELECT DATE(NOW()) dt) AAAA) AAA) AA) A;
+---------------------+---------------------+
| thu_beg             | wed_end             |
+---------------------+---------------------+
| 2011-09-15 00:00:00 | 2011-09-21 23:59:59 |
+---------------------+---------------------+
1 row in set (0.00 sec)

只需将现在的()函数调用用您喜欢的任何日期替换,您将在周四开始一周,以便您选择的给予时间。

这是使用特定日期'2011-01-01'的另一个示例

mysql> SELECT
    -> thuwk_beg + INTERVAL 0 second thu_beg,
    -> thuwk_beg + INTERVAL 604799 second wed_end
    -> FROM (SELECT (DATE('2011-01-01') - INTERVAL daysbacktothursday DAY) thuwk_beg
    -> FROM (SELECT SUBSTR('3456012',wkndx,1) daysbacktothursday
    -> FROM (SELECT DAYOFWEEK(dt) wkndx FROM (SELECT DATE('2011-01-01') dt) AAAA) AAA) AA) A;
+---------------------+---------------------+
| thu_beg             | wed_end             |
+---------------------+---------------------+
| 2010-12-30 00:00:00 | 2011-01-05 23:59:59 |
+---------------------+---------------------+
1 row in set (0.00 sec)

您的查询 table 今天的引用将类似于这样:

SELECT * from `table`,
(SELECT thuwk_beg + INTERVAL 0 second thu_beg,
thuwk_beg + INTERVAL 604799 second wed_end
FROM (SELECT (DATE(NOW()) - INTERVAL daysbacktothursday DAY) thuwk_beg
FROM (SELECT SUBSTR('3456012',wkndx,1) daysbacktothursday
FROM (SELECT DAYOFWEEK(dt) wkndx FROM (SELECT DATE(NOW()) dt) AAAA) AAA) AA) A) M
WHERE `date` >= thu_beg
AND `date` <= wed_end;

试试看 !!!

更新2011-09-22 16:27 EDT

这是我提出的标记thu wed的疑问。

SELECT thuwk_beg + INTERVAL 0 second thu_beg,
thuwk_beg + INTERVAL 604799 second wed_end
FROM (SELECT (DATE(NOW()) - INTERVAL daysbacktothursday DAY) thuwk_beg
FROM (SELECT SUBSTR('3456012',wkndx,1) daysbacktothursday
FROM (SELECT DAYOFWEEK(dt) wkndx FROM (SELECT DATE(NOW()) dt) AAAA) AAA) AA) A;

其他几周怎么样???

  • (SELECT SUBSTR('6012345',wkndx,1) 一周开始蒙蒙的阳光吗
  • (SELECT SUBSTR('5601234',wkndx,1) 一周开始周二结束
  • (SELECT SUBSTR('4560123',wkndx,1) 一周开始结婚结局
  • (SELECT SUBSTR('3456012',wkndx,1) 一周开始thu结束了
  • (SELECT SUBSTR('2345601',wkndx,1) 一周开始星期五结束了
  • (SELECT SUBSTR('1234560',wkndx,1) 一周开始星期六结束星期五吗
  • (SELECT SUBSTR('0123456',wkndx,1) 一周开始太阳结束星期六吗

其他提示

让我重申您要的东西,以确保我做对了:

您想在过去7天中提取所有记录吗?

看起来像:

select * from table where `date` between $date - interval 7 day and $date

重要的是要注意,$ date不是字面的mysql语法,而只是您想要的开始日期的示例位置。如果这是为了报告,我认为查询最终将是从某些脚本生成的?如果这是真的,那么在该语言中可能会更简单,然后作为构造查询的一部分传递字面价值。

我很喜欢让查询尽可能简单,所以我会这样。我将为其他人留出空间,以便在单个SQL-FU查询中完成您想要的内容。

编辑: 重读帖子后,似乎您可能正在使用日期类型。在这种情况下,以下斜体中的块可能是多余的。如果我花时间写它,我将留下它,因为这对他人很有帮助。

您说您正在使用“ Datestamp”?从技术上讲,这不是MySQL数据类型。是日期时间,时间戳还是日期(时间和年也存在,但从您的上下文中,我觉得这些不适用)?我问,因为你 可能 想要使其仅仅是日期列而不是其他列。如果这是正确的选择,则确实取决于列如何使用列的细节以及对所有列的查询。如果唯一的目的只是将记录拉到日期范围内,无论时间如何,那么日期绝对是必经之路。首先,它只需要3个字节而不是4个字节。您可以找到有关不同类型的详细信息http://dev.mysql.com/doc/refman/5.0/en/datetime.html

http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html

如果并且仅当您专门使用日期时,您才能考虑以下内容:

用“解释”前缀运行查询。有关如何解释输出以及最好的内容的详细信息可以找到 http://dev.mysql.com/doc/refman/5.0/en/explain-xutput.html

一旦有解释,请更改查询

select * from table where date in ("N", "N+1"..."N+7")

在您列举所有您感兴趣的个人日期的地方。我遇到的情况很明显MySQL不够聪明,无法有效地使用范围查询(即X和Y之间的范围),从而将特定值列举为小集合。

如果您根据其值进行定期报告查询,则需要确保索引该列的哪种用例。

@Rolando先生显然回答了这个问题,但我将提出另一个决定,该决定将使您能够在时区和最重要的组之间操纵和自定义日历,这些日历在不同时区定义

因此,让我们假设您的MySQL正在UTC配置的服务器上运行,并且您想拥有一个提前7个小时的自定义日历,因此您的几周应在星期六7 AM开始

CREATE TABLE `wh_blur_calendar` (
  `date` timestamp NOT NULL ,
  `y` smallint(6) DEFAULT NULL,
  `q` tinyint(4) DEFAULT NULL,
  `m` tinyint(4) DEFAULT NULL,
  `d` tinyint(4) DEFAULT NULL,
  `w` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `wh_ints` (
  `i` tinyint(4) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into wh_ints values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);

现在,一个受欢迎的笛卡尔加入应该填充您的桌子:

INSERT INTO wh_blur_calendar (date)
SELECT DATE('2010-01-01 00:00:00 ') + INTERVAL a.i*10000 + b.i*1000 + c.i*100 + d.i*10 + e.i DAY
FROM wh_ints a JOIN wh_ints b JOIN wh_ints c JOIN wh_ints d JOIN wh_ints e
WHERE (a.i*10000 + b.i*1000 + c.i*100 + d.i*10 + e.i) < 10245
ORDER BY 1;

让我们更新时间:

update  db_wh_repo.wh_blur_calendar set date = date_add(date, interval 7 hour);

最后以自定义方式安排日历的一周

UPDATE wh_blur_calendar
SET 
    y = YEAR(date),
    q = quarter(date),
    m = MONTH(date),
    d = dayofmonth(date),
    w = week(date_add((date), interval 1 day));

相信我,我花了几个小时来提出这个决定,但是如果您想根据自定义时区和周定义进行分组结果,它为您提供了很多自由。

许可以下: CC-BY-SA归因
不隶属于 dba.stackexchange
scroll top