简体   繁体   English

从具有创建日期的表中获取上周的数据

[英]Get last week's data from a table with a creation date

Using the following query for retrieving last week data,but I am getting error as 使用以下查询检索上周数据,但我收到错误

Postgres ERROR: syntax error at or near "CAST" Position: 127 Postgres ERROR:语法错误在“CAST”或附近位置:127

I don't know where the error is: 我不知道错误在哪里:

SELECT count(*), extract(day from createdon) AS period
FROM orders
WHERE servicename =:serviceName AND  createdon BETWEEN 
    CAST(NOW() AS CAST(DATE-EXTRACT(DOW FROM NOW()) AS INTEGER-7)) AND
    CAST(NOW() AS CAST(DATE-EXTRACT(DOW from NOW()) AS INTEGER))
GROUP BY  extract(day from createdon)
ORDER BY extract(day from createdon);

You are overcomplicating things. 你太复杂了。 To get last week's data, just get everything after the "start of this week" minus 7 days: 要获得上周的数据,只需在“本周开始”减去7天后获取所有内容:

The "start of the this week" can be evaluated using date_trunc('week', current_date) . 可以使用date_trunc('week', current_date)来评估date_trunc('week', current_date)

If you subtract 7 days you get the start of the previous week: date_trunc('week', current_date) - interval '7' day . 如果你减去7天就可以获得前一周的开始date_trunc('week', current_date) - interval '7' day If you subtract 1 day, you get the end of the previous week. 如果减去1天,则会得到前一周的结束

date_trunc always uses Monday as the start of the week, so if your week starts on Sunday, just subract one more, eg date_trunc('week', current_date)::date - 8 will be the Sunday of the previous week date_trunc总是使用星期一作为星期的开始,所以如果你的星期在星期日开始,只需减去一个,例如date_trunc('week', current_date)::date - 8将是前一周的星期日

Putting that all together you get: 把这一切放在一起你会得到:

SELECT count(*), extract(day from createdon) AS period
FROM orders
WHERE servicename =:serviceName 
  AND createdon 
      between date_trunc('week', current_date)::date - 7 
          and date_trunc('week', current_date)::date - 1
GROUP BY extract(day from createdon)
ORDER BY extract(day from createdon);

If your columns are timestamp columns you can simply cast createdon to a date to get rid of the time part: 如果您的列是时间戳列,您可以简单地将createdon转换为日期以摆脱时间部分:

  AND createdon::date 
      between date_trunc('week', current_date)::date - 7 
          and date_trunc('week', current_date)::date

Note that a regular index on createdon will not be used for that condition, you would need to create an index on createdon::date if you need the performance. 请注意, createdon上的常规索引不会用于该条件,如果需要性能,则需要在createdon::date上创建索引。

If you can't (or don't want to) create such an index, you need to use something different then between 如果你不能(或不愿)创建这样的索引,你需要使用不同的东西,然后between

  AND createdon >= date_trunc('week', current_date)::date - 7 
  AND createdon < date_trunc('week', current_date)::date

(Note the use of < instead of <= which is what `between is using) (注意使用<而不是<=这是什么`之间正在使用)

Another option is to convert the date information to a combination of week and year: 另一种选择是将日期信息转换为星期和年份的组合:

AND to_char(createdon, 'iyyy-iw') = to_char(date_trunc('week', current_date)::date - 7, 'iyyy-iw')

Note, that I used the ISO week definition for the above. 请注意,我使用了上面的ISO周定义 If you are using a different week numbering system, you need a different format mask for the to_char() function. 如果您使用的是不同的周编号系统,则需要为to_char()函数使用不同的格式掩码

If you work with the North American week system (whose weeks start on Sunday), your original approach was good enough, just use the correct syntax of CAST(<epr> AS <type>) : 如果您使用的是北美周系统(周周从周日开始),那么您的原始方法就足够了,只需使用正确的CAST(<epr> AS <type>)语法CAST(<epr> AS <type>)

SELECT   COUNT(*),
         EXTRACT(DAY FROM createdon) period
FROM     orders
WHERE    servicename = 'Cell Tower Monitoring'
AND      createdon BETWEEN CURRENT_DATE - CAST(EXTRACT(DOW FROM CURRENT_DATE) AS INTEGER) - 7 
                       AND CURRENT_DATE - CAST(EXTRACT(DOW FROM CURRENT_DATE) AS INTEGER) - 1
GROUP BY EXTRACT(DAY FROM createdon)
ORDER BY EXTRACT(DAY FROM createdon);

Note : this assumes that createdon is a DATE column. 注意 :这假设createdonDATE列。 If it's a TIMESTAMP (or TIMESTAMP WITH TIME ZONE ), you need a slightly different version: 如果它是TIMESTAMP (或TIMESTAMP WITH TIME ZONE ),则需要稍微不同的版本:

SELECT   COUNT(*),
         EXTRACT(DAY FROM createdon) period
FROM     orders
WHERE    servicename = 'Cell Tower Monitoring'
AND      createdon >= CURRENT_TIMESTAMP - INTERVAL '1 day' * (EXTRACT(DOW FROM CURRENT_TIMESTAMP) + 7)
AND      createdon <  CURRENT_TIMESTAMP - INTERVAL '1 day' *  EXTRACT(DOW FROM CURRENT_TIMESTAMP)
GROUP BY EXTRACT(DAY FROM createdon)
ORDER BY EXTRACT(DAY FROM createdon);

If you want to use the ISO week system (whose weeks start on Monday), then just use ISODOW instead of DOW . 如果你想使用ISO周系统(周周从星期一开始),那么只需使用ISODOW而不是DOW Or, you could use the date_trunc('week', ...) function, like in @a_horse_with_no_name's answer . 或者,您可以使用date_trunc('week', ...)函数,例如@ a_horse_with_no_name的答案

If you want to use another week systems (f.ex. which starts on Saturday), you'll need some extra logic inside CASE expressions, as subtracting 1 from DOW will not give the expected results at the start of that kind of week (f.ex. on Saturday it would give the week 2 weeks before). 如果你想使用另一个周系统(f.ex.从星期六开始),你需要在CASE表达式中有一些额外的逻辑,因为从DOW减去1将不会在那周的开始时给出预期的结果(星期六f.ex.将在2周前给出一周)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM