PHP query, get results for the last 7 days ("complete" days) - sql

I have this query, which output number of rows per day for the last 7 days.
How do I change it, so I only get "complete days"? meaning: results from today will not be counted (since today is not "finished").
SELECT date(downloaddate), COUNT(id) AS num_downloads,
SUM(filesize) AS daily_filesize
FROM downloads
WHERE downloaddate > now() - INTERVAL 1 WEEK
GROUP BY date(downloaddate)

Use curdate(). Unlike now() it doesn't include the time so you are effectively comparing downloaddate against today's date with time of '00:00:00' (start of day).
ie.
SELECT date(downloaddate), COUNT(id) AS num_downloads,
SUM(filesize) AS daily_filesize
FROM downloads
WHERE downloaddate < CURDATE()
AND downloaddate > CURDATE() - INTERVAL 1 WEEK
GROUP BY date(downloaddate)

You're already using date() to get the date part. Extend it's use into the where clause, or use curdate() as a shorthand for date(now()), like:
WHERE downloaddate BETWEEN curdate()
AND curdate() - INTERVAL 1 WEEK)
This will grab 7 whole days, ending last midnight.

Related

How to make POSTGRESQL query based on first 2 parameters and latest third parameter

I have DB:
**client_id | Version | Date(year, month, day)**
I need to make query request for last year(or last 12 months) group by Client_id, Version and latest date(!) for them.
For example:
client_id | Version | **LATEST** Date
23 v2 2022-1-25
23 v1 2021-3-23
25 v0 2021-6-23
This is what I have right now:
SELECT client_id, Version, Date
FROM db_table
WHERE date >= '2022-01-01' AND date < NOW()::DATE
GROUP BY client_id, Version, Date
And I'm getting result for EVERY DAY. If I'm removing DATE from group by, its complaining that Date should be in Group by.
I hope I did describe everything properly. I'm new here, so please let me know if I provide not full info.
Thank you for your time.
To get the most recent full year (i.e. not including the partial current day),
SELECT current_date - interval '1 year'; --this returns 2021-02-07 when run today
To consider today as part of the 12 month period, then:
SELECT current_date - interval '1 year - 1 day'; --this returns 2021-02-08 when run today
So, assuming that you want the former option (you can switch it if you like):
SELECT client_id, "Version", MAX("Date") AS latest_date
FROM db_table
WHERE "Date" BETWEEN current_date - interval '1 year' AND current_date
GROUP BY client_id, "Version";
p.s. recommend you don't use "Date" as a column name since it's a reserved word, and avoid using upper case letters in column names :)

SQL : retrieve top 7 of entries added in the past week

I’m new to SQL and I need some help for a query that should return a top of occurrences sorted by date.
Actually I have a table to which are added searches done by users alongside the date of search (column is in the DATETIME format).
What I would like to do is to create a list of « Trending searches » that would show the top 7 searches done over the past week (Sunday to Sunday for example) but I’m unsure where to start.
I’ve heard of the DATEPART function but I don’t know how to use it alongside a top 7 occurrences.
Thanks in advance for your help and have a nice day !
Does this work?
declare #lastweek datetime
declare #now datetime
set #now = getdate()
set #lastweek = dateadd(day,-7,#now)
SELECT COUNT(g.searchTerm) AS appearanceCount, g.searchTerm FROM DesiredTable AS g
WHERE g.DateSearched BETWEEN #lastweek AND #now
GROUP BY(GameTypeId)
ORDER BY (appearanceCount) DESC
The mention of datepart() suggests SQL Server. If so, you can do:
select top (7) s.searchTerm, count(*)
from searches s
where s.searchTime >= dateadd(day, -7, getdate())
group by s.searchTerm
order by count(*) desc;
This gets the last 7 days to the current time.
If you want the last week, a pretty simple where is:
where datediff(week, s.searchTime, getdate()) = 1
This problem is solvable pretty easy with mysql. You are trying to do multiple things, as far as I understood:
1. Get searches from last week
With DATETIME fields there are pretty easy ways to extract the week of the year:
SELECT id FROM searches
WHERE searchDate >= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY
AND searchDate < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY
As suggested here.
2. Get the top 7 most frequent ones
Secondly you said that you want to have the top 7 searches, which translate into most frequent occurring search terms. In other words: You need to group identical search terms together and count them:
SELECT count(id), searchTerm FROM searches
WHERE searchDate >= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY
AND searchDate < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY
GROUP BY searchTerm
in addition:
To get the first n (here 7) rows use rownum<=7.
Like this (added to Gegenwinds solution):
SELECT result.* FROM
(SELECT count(id), searchTerm FROM searches
WHERE searchDate >= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY
AND searchDate < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY
GROUP BY searchTerm) result
ORDER BY count(id) DESC
WHERE rownum<= 7

Sql query to return data if AVG(7 days record count) > (Today's record count)

I want to write a SQL query in Oracle database for:
A priceindex(field name) have around 120(say) records each day and I have to display the priceindex name and today's date, if the avg of last 7 days record count is greater than Todays record count for the priceindex(group by priceindex).
Basically, There will be 56 priceindex and each should have around 120 records each day and is dump to database each day from external site. So want to make sure all records are downloaded to the database everyday.
Except for the clarification I requested in a Comment to your question (having to do with "how can we know today's final count, when today is not over yet), the problem can be solved along the following lines. Not tested since you didn't provide sample data.
From your table, select only the rows where the relevant DATE is between "today" - 7 and "today" (so there are really EIGHT days: the seven days preceding today, and today). Then group by PRICEINDEX. Count total rows for each group, and count rows just for "today". The rows for "today" should be less than 1/8 times the total count (this is easy algebra: this is equivalent to being less than 1/7 times the count of OTHER days).
Such conditions, at the group level, must be in the HAVING clause.
select priceindex
from your_table
where datefield >= trunc(sysdate) - 7 and datefield < trunc(sysdate) + 1
group by priceindex
having count(case when datefield >= trunc(sysdate) then 1 end) < 1/8 * count(*)
;
EDIT The OP clarified that the query runs every day at midnight; this means that "today" should actually mean "yesterday" (the day that just ended). In Oracle, and probably in all of computing, midnight belongs to the day that BEGINS at midnight, not the one that ends at midnight. The time-of-day at midnight is 00:00:00 (beginning of the new day), not 24:00:00.
So, the query above will have to be changed slightly:
select priceindex
from your_table
where datefield >= trunc(sysdate) - 8 and datefield < trunc(sysdate)
group by priceindex
having count(case when datefield >= trunc(sysdate) - 1 then 1 end)
< 1/8 * count(*)
;

Get average for "last month" only

Pretty new to SQL and have hit a roadblock.
I have this query, which works fine:
SELECT
(COUNT(*)::float / (current_date - '2017-05-17'::date)) AS "avg_per_day"
FROM "table" tb;
I now want it to include only data from the last month, not all time.
I've tried doing something along the lines of:
SELECT
(COUNT(*)::float / (current_date - (current_date - '1 month' ::date)) AS "avg_per_day"
FROM "table" tb;
The syntax is clearly wrong, but I am not sure what the right answer is. Have googled around and tried various options to no avail.
I can't use a simple AVG because the number I require is an AVG per day for the last month of data. Thus I've done a count of rows divided by the number of days since the first occurrence to get my AVG per day.
I have a column which tells me the date of the occurrence, however there are multiple rows with the same date in the dataset. e.g.
created_at
----------------------------
Monday 27th June 2017 12:00
Monday 27th June 2017 13:00
Tuesday 28th June 2017 12:00
and so on.
I am counting the number of occurrences per day and then need to work out an average from that, for the last month of results only (they date back to May).
The answer depends on the exact definition of "last month" and the exact definition of "average count".
Assuming:
Your column is defined created_at timestamptz NOT NULL
You want the average number of rows per day - days without any rows count as 0.
Cover 30 days exactly, excluding today.
SELECT round(count(*)::numeric / 30, 2) -- simple now with a fixed number of days
FROM tbl
WHERE created_at >= (now()::date - 30)
AND created_at < now()::date -- excl. today
Rounding is optional, but you need numeric instead of float to use round() this way.
Not including the current day ("today"), which is ongoing and may result in a lower, misleading average.
If "last month" is supposed to mean something else, you need to define it exactly. Months have between 28 and 31 days, this can mean various things. And since you obviously operate with timestamp or timestamptz, not date, you also need to be aware of possible implications of the time of day and the current time zone. The cast to date (or the definition of "day" in general) depends on your current timezone setting while operating with timestamptz.
Related:
Ignoring timezones altogether in Rails and PostgreSQL
Select today's (since midnight) timestamps only
Subtract hours from the now() function
I think you just need a where clause:
SELECT
(COUNT(*)::float / (current_date - (current_date - '1 month' ::date)) AS "avg_per_day"
FROM "table" tb
WHERE created_at > (current_date - '1 month' ::date)
I believe Postgresql and other RDBMS has AVG() to calculate average.
SELECT AVG(tb.columnName) AS avg_per_month
FROM someTable tb
WHERE
tb.createdDate >= [start date of month] AND
tb.createdDate <= [end date of month]
Edit: I subtract current date with INTERVAL. I am on mobile phone so I cannot test.
SELECT
(COUNT(*)::float / (current_date - ( current_date - INTERVAL '1 month')) AS "avg_per_day"
FROM "table" tb;

Group SQL results by week and specify "week-ending" day

I'm trying to select data grouped by week, which I have working, but I need to be able to specify a different day as the last day of the week. I think something needs to go near INTERVAL (6-weekday('datetime')) but not sure. This kind of SQL is above my pay-grade ($0) :P
SELECT
sum(`value`) AS `sum`,
DATE(adddate(`datetime`, INTERVAL (6-weekday(`datetime`)) DAY)) AS `dt`
FROM `values`
WHERE id = '123' AND DATETIME BETWEEN '2010-04-22' AND '2010-10-22'
GROUP BY `dt`
ORDER BY `datetime`
Thanks!
select
sum(value) as sum,
CASE WHEN (weekday(datetime)<=3) THEN date(datetime + INTERVAL (3-weekday(datetime)) DAY)
ELSE date(datetime + INTERVAL (3+7-weekday(datetime)) DAY)
END as dt
FROM values
WHERE id = '123' and DATETIME between '2010-04-22' AND '2010-10-22'
GROUP BY dt
ORDER BY datetime
This does look pretty evil but, this query will provide you with a sum of value grouped by a week ending on a Thursday (weekday() return of 3).
If you wish to change what day the end of the week is you just need to replace the 3's in the case statement, ie if you wanted Tuesday you would have it say
CASE WHEN (weekday(datetime)<=1) THEN date(datetime + INTERVAL (1-weekday(datetime)) DAY)
ELSE date(datetime + INTERVAL (1+7-weekday(datetime)) DAY)
I hope this helps.
Simple solution that I like. This will return the date for the start of the week assuming the week ends Sunday and starts Monday.
DATE(`datetime`) - INTERVAL WEEKDAY(`datetime`) AS `dt`
This can easily be adjusted to have a week ending on Thursday because Thursday is 3 days earlier than Sunday
DATE(`datetime`) - INTERVAL WEEKDAY(`datetime` + INTERVAL 3 DAY) AS `dt`
this returns for the start of the week that starts on Friday and ends on Thursday.
You can group on this no problem. If you want to use get the end of the week based on the start you do this
DATE(`datetime`) - INTERVAL -6 + WEEKDAY(`datetime` + INTERVAL 3 DAY) AS `dt`
I think you must choose between Sunday and Monday? When you can use DATE_FORMAT for grouping by string format of date, and use %v for grouping by Mondays and %v for grouping by Sundays.
SELECT
sum(`value`) AS `sum`,
DATE_FORMAT(`datetime`,'%v.%m.%Y') AS `dt`
FROM `values`
WHERE id = '123' AND DATETIME BETWEEN '2010-04-22' AND '2010-10-22'
GROUP BY DATE_FORMAT(`datetime`,'%v.%m.%Y')
ORDER BY `datetime`
How to use DATE_FORMAT
I don't remember the exact math, but you can get WEEKDAY to wrap around on different days of the week by adding or subtracting days to its argument. You'll need to tinker with different values of x and y in the expression:
x-weekday(adddate(`datetime`, INTERVAL y DAY))