How do I get a maximium daily value of a numerical field over a year in SQL - sql

How do I get a maximium daily value of a numerical field over a year in MS-SQL

This would query the daily maximum of value over 2008:
select
datepart(dayofyear,datecolumn)
, max(value)
from yourtable
where '2008-01-01' <= datecolumn and datecolumn < '2009-01-01'
group by datepart(dayofyear,datecolumn)
Or the daily maximum over each year:
select
datepart(year,datecolumn),
, datepart(dayofyear,datecolumn)
, max(value)
from yourtable
group by datepart(year,datecolumn), datepart(dayofyear,datecolumn)
Or the day(s) with the highest value in a year:
select
Year = datepart(year,datecolumn),
, DayOfYear = datepart(dayofyear,datecolumn)
, MaxValue = max(MaxValue)
from yourtable
inner join (
select
Year = datepart(year,datecolumn),
, MaxValue = max(value)
from yourtable
group by datepart(year,datecolumn)
) sub on
sub.Year = yourtable.datepart(year,datecolumn)
and sub.MaxValue = yourtable.value
group by
datepart(year,datecolumn),
datepart(dayofyear,datecolumn)

You didn't mention which RDBMS or SQL dialect you're using. The following will work with T-SQL (MS SQL Server). It may require some modifications for other dialects since date functions tend to change a lot between them.
SELECT
DATEPART(dy, my_date),
MAX(my_number)
FROM
My_Table
WHERE
my_date >= '2008-01-01' AND
my_date < '2009-01-01'
GROUP BY
DATEPART(dy, my_date)
The DAY function could be any function or combination of functions which gives you the days in the format that you're looking to get.
Also, if there are days with no rows at all then they will not be returned. If you need those days as well with a NULL or the highest value from the previous day then the query would need to be altered a bit.

Something like
SELECT dateadd(dd,0, datediff(dd,0,datetime)) as day, MAX(value)
FROM table GROUP BY dateadd(dd,0, datediff(dd,0,datetime)) WHERE
datetime < '2009-01-01' AND datetime > '2007-12-31'
Assuming datetime is your date column, dateadd(dd,0, datediff(dd,0,datetime)) will extract only the date part, and then you can group by that value to get a maximum daily value. There might be a prettier way to get only the date part though.
You can also use the between construct to avoid the less than and greater than.

Group on the date, use the max delegate to get the highest value for each date, sort on the value, and get the first record.
Example:
select top 1 theDate, max(theValue)
from TheTable
group by theDate
order by max(theValue) desc
(The date field needs to only contain a date for this grouping to work, i.e. the time component has to be zero.)
If you need to limit the query for a specific year, use a starting and ending date in a where claues:
select top 1 theDate, max(theValue)
from TheTable
where theDate between '2008-01-01' and '2008-12-13'
group by theDate
order by max(theValue) desc

Related

SQL How can I get a count of messages going out by month

I have a table that sends out messages, I would like to get a total count of the messages that have been going out month by month over the last year . I am new to SQL so I am having trouble with it . I am using MSSQL 2012 this is my sql
SELECT sentDateTime, MessageID, status AS total, CONVERT(NVARCHAR(10), sentDateTime, 120) AS Month
FROM MessageTable
WHERE CAST(sentDateTime AS DATE) > '2017-04-01'
GROUP BY CONVERT(NVARCHAR(10), sentDateTime, 120), sentDateTime, MessageID, status
ORDER BY Month;
I think the month() and year() functions are more convenient than datepart() for this purpose.
I would go for:
select year(sentDateTime) as yr, month(sentDateTime) as mon, count(*)
from MessageTable
where sentDateTime > '2017-04-01'
group by year(sentDateTime), month(sentDateTime)
order by min(sentDateTime);
Additional notes:
Only include the columns in the select that you care about. This would be the ones that define the month and the count.
Only include the columns in the group by that you care about. Every combination of the expressions in the group by found in the data define a column.
There is no need to convert sentDateTime to a date explicitly for the comparison.
The order by orders the results by time. Using the min() is a nice convenience.
Including the year() makes sure you don't make a mistake -- say by including data from 2018-04 with 2017-04.
-- this selects the part of the date you are looking for, replace this with the date format you are using, this should give you what you are looking for
SELECT DATEPART(mm, GETDATE())
SELECT COUNT(DATEPART(mm, sentDateTime)), MessageID, status
From MessageTable where Cast(sentDateTime as date) > '2017-04-01'
group by DATEPART(mm, sentDateTime), MessageID, status
order by DATEPART(mm, sentDateTime)
You can group by the month number of the sentDateTime with the function DATEPART(MONTH, sentDateTime). The next select will also yield results if no message was sent for a particular month (total = 0).
;WITH PossibleMonths AS
(
SELECT
M.PossibleMonth
FROM
(VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) M(PossibleMonth)
),
MonthTotals AS
(
select
COUNT(1) AS Total,
DATEPART(MONTH, sentDateTime) [Month]
From
MessageTable
where
Cast(sentDateTime as date) > '2017-04-01'
group by
DATEPART(MONTH, sentDateTime)
)
SELECT
P.PossibleMonth,
Total = ISNULL(T.Total, 0)
FROM
PossibleMonths AS P
LEFT JOIN MonthTotals AS T ON P.PossibleMonth = T.Month

How do I calculate how many X requests were open as of each date?

Using
https://data.seattle.gov/Public-Safety/PDRs-After-using-City-of-Seattle-Public-Records-Re/wj44-r6br/data I want the know on each date the number of public disclosure requests were open. This means per date I want the number of requests created before or same day as date and don't have a close date after the date.
I copied it to https://data.world/timacbackup/seattle-police-public-disclosure-requests where I can use SQL.
The closest I've gotten is
SELECT CAST(seattle_police_records_requests.request_create_date AS DATE) AS the_date,
count(*)
FROM seattle_police_records_requests
GROUP BY CAST(seattle_police_records_requests.request_create_date AS DATE)
ORDER BY the_date DESC;
I tried
SELECT CAST(request_create_date AS DATE) AS the_date,
count((
SELECT request_create_date
FROM seattle_police_records_requests AS t
WHERE CAST(t.request_create_date AS DATE) < d.request_create_date
))
FROM seattle_police_records_requests AS d
GROUP BY CAST(request_create_date AS DATE)
ORDER BY the_date DESC;
but get unknown table 'd' for the count subquery.
The last query I tried is
WITH dates
AS (
SELECT CAST(request_create_date AS DATE) AS create_date,
CAST(request_closed_date AS DATE) AS closed_date
FROM seattle_police_records_requests
),
create_dates
AS (
SELECT DISTINCT CAST(request_create_date AS DATE) AS create_date
FROM seattle_police_records_requests
)
SELECT create_dates.create_date,
COUNT(*)
FROM dates
INNER JOIN create_dates ON dates.create_date = create_dates.create_date
GROUP BY create_dates.create_date
HAVING dates.create_date <= create_dates.create_date
ORDER BY create_dates.create_date DESC
and basically it's just counting # of requested opened on given day not all that were open as of given day.
After importing the "created" and "closed" values into SQL Server as datetime columns I was able to generate the counts per day like so:
WITH
given_dates AS
(
SELECT DISTINCT CAST(created AS DATE) AS given_date
FROM seattle_police_records_requests
)
SELECT
given_date,
(
SELECT COUNT(*)
FROM seattle_police_records_requests
WHERE created <= DATEADD(DAY, 1, given_date) AND (closed > given_date OR closed IS NULL)
) AS num_open
FROM given_dates
ORDER BY given_date;
The DATEADD was necessary to include requests opened during that day, since the comparison of a date and a datetime implies that the date value is midnight (i.e., the very beginning of that day).

How to query database for rows from next 5 days

How can I make a query in SQL Server to query for all rows for the next 5 days.
The problem is that it has to be days with records, so the next 5 days, might become something like, Today, Tomorrow, some day in next month, etc...
Basically I want to query the database for the records for the next non empty X days.
The table has a column called Date, which is what I want to filter.
Why not split the search into 2 queries. First one searches for the date part, the second uses that result to search for records IN the dates returned by the first query.
#Anagha is close, just a little modification and it is OK.
SELECT *
FROM TABLE
WHERE DATE IN (
SELECT DISTINCT TOP 5 DATE
FROM TABLE
WHERE DATE >= referenceDate
ORDER BY DATE
)
You can use following SQL query where 5 different dates are fetched at first then all rows for those selected dates are displayed
declare #n int = 5;
select *
from myData
where
datecol in (
SELECT distinct top (#n) cast(datecol as date) as datecol
FROM myData
WHERE datecol >= '20180101'
ORDER BY datecol
)
Try this:
select date from table where date in (select distinct top 5 date
from table where date >= getdate() order by date)
If your values are dates, you can use `dense_rank():
select t.*
from (select t.*, dense_rank() over (order by datecol) as seqnum
from t
where datecol >= cast(getdate() as date)
) t
where seqnum <= 5;
If the column has a time component and you still want to define days by midnight-to-midnight (as suggested by the question), just convert to date:
select t.*
from (select t.*,
dense_rank() over (order by cast(datetimecol as date)) as seqnum
from t
where datetimecol >= cast(getdate() as date)
) t
where seqnum <= 5;

Fetch records week wise for last one year in MS SQL

I have table with users data.Columns are Username,Datetime.
I need to fetch count of users weekly wise for last one year data from current date.
I wrote query to fetch last one year's record daywise but I couldn't find a way to retrieve data in weekly wise.
Below is the query to fetch data in day wise.
select count(Username)
from tablename
where (Datetime > DATEADD(year,-1,GETDATE()) and Datetime< GETDATE()-1)
group by Datetime
order by Datetime asc
Can anyone help me to fetch the weekwise count for the same in sql server?
TRY THIS: you have to group by week so you can done in the following way:
SELECT COUNT(Username)
from tablename
where (Datetime > DATEADD(year,-1,GETDATE()) and DATETIME < GETDATE()-1)
group by DATEPART(wk,[DATETIME])
order by [Datetime] ASC
Note: Please try to avoid reserved words as column name and you can enclosed existing one in [].
Use DATEPART IN GROUP BY clause.In where condition first filter one year record and then group by based on DATEPART function to get week wise count
SELECT COUNT(Username) , DATEPART(WEEK,Datetime)
FROM tablename
WHERE DATEDIFF(YEAR,Datetime,GETDATE()) <= 0 AND
DATEDIFF(YEAR,Datetime,DATEADD(YEAR,-1,GETDATE())) >= 0
GROUP BY DATEPART(WEEK,Datetime)
You can just change the group by and order by clause as below.
group by datepart(week,Datetime)
order by datepart(week,Datetime) asc
First, you need to specify extra column, pointing which week of the year it is.
You can create it like this (I assume that you have data from more years and let's call our column Date):
CASE WHEN Date BETWEEN '2017-01-01 00:00:00.000' AND '2018-01-01 00:00:00.000'
THEN floor(cast(datediff(dd, '2017-01-01 00:00:00.000',Date) as real) / 7)
END AS [Week]
Secondly, you have to run the query:
SELECT COUNT(Username) FROM tablename
GROUP BY [Week]
SELECT *, WEEK(created_on) week
FROM Table_Name
WHERE created_on > DATEADD(year,-1,GETDATE())
ORDER BY week

Add one for every row that fulfills where criteria between period

I have a Postgres table that I'm trying to analyze based on some date columns.
I'm basically trying to count the number of rows in my table that fulfill this requirement, and then group them by month and year. Instead of my query looking like this:
SELECT * FROM $TABLE WHERE date1::date <= '2012-05-31'
and date2::date > '2012-05-31';
it should be able to display this for the months available in my data so that I don't have to change the months manually every time I add new data, and so I can get everything with one query.
In the case above I'd like it to group the sum of rows which fit the criteria into the year 2012 and month 05. Similarly, if my WHERE clause looked like this:
date1::date <= '2012-06-31' and date2::date > '2012-06-31'
I'd like it to group this sum into the year 2012 and month 06.
This isn't entirely clear to me:
I'd like it to group the sum of rows
I'll interpret it this way: you want to list all rows "per month" matching the criteria:
WITH x AS (
SELECT date_trunc('month', min(date1)) AS start
,date_trunc('month', max(date2)) + interval '1 month' AS stop
FROM tbl
)
SELECT to_char(y.mon, 'YYYY-MM') AS mon, t.*
FROM (
SELECT generate_series(x.start, x.stop, '1 month') AS mon
FROM x
) y
LEFT JOIN tbl t ON t.date1::date <= y.mon
AND t.date2::date > y.mon -- why the explicit cast to date?
ORDER BY y.mon, t.date1, t.date2;
Assuming date2 >= date1.
Compute lower and upper border of time period and truncate to month (adding 1 to upper border to include the last row, too.
Use generate_series() to create the set of months in question
LEFT JOIN rows from your table with the declared criteria and sort by month.
You could also GROUP BY at this stage to calculate aggregates ..
Here is the reasoning. First, create a list of all possible dates. Then get the cumulative number of date1 up to a given date. Then get the cumulative number of date2 after the date and subtract the results. The following query does this using correlated subqueries (not my favorite construct, but handy in this case):
select thedate,
(select count(*) from t where date1::date <= d.thedate) -
(select count(*) from t where date2::date > d.thedate)
from (select distinct thedate
from ((select date1::date as thedate from t) union all
(select date2::date as thedate from t)
) d
) d
This is assuming that date2 occurs after date1. My model is start and stop dates of customers. If this isn't the case, the query might not work.
It sounds like you could benefit from the DATEPART T-SQL method. If I understand you correctly, you could do something like this:
SELECT DATEPART(year, date1) Year, DATEPART(month, date1) Month, SUM(value_col)
FROM $Table
-- WHERE CLAUSE ?
GROUP BY DATEPART(year, date1),
DATEPART(month, date1)