如何通过每周的成绩来改善我的SQL声明,并在周四或一周的其他任何一天开始一周?
题
我是一个全新的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));
相信我,我花了几个小时来提出这个决定,但是如果您想根据自定义时区和周定义进行分组结果,它为您提供了很多自由。