简体   繁体   中英

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

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:

The "start of the this week" can be evaluated using 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 . If you subtract 1 day, you get the end of the previous week.

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

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:

  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.

If you can't (or don't want to) create such an index, you need to use something different then 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. If you are using a different week numbering system, you need a different format mask for the to_char() function.

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>) :

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. If it's a TIMESTAMP (or TIMESTAMP WITH TIME ZONE ), you need a slightly different version:

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 . Or, you could use the date_trunc('week', ...) function, like in @a_horse_with_no_name's answer .

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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