How do I return all rows of data from min date to the next possible date after current date in date column? - sql

Consider a table with multiple rows with dates:
Date
------
5/9/2022
5/27/2022
4/18/2022
6/2/2022
7/1/2022
6/6/2022
7/8/2022
7/6/2022
7/22/2022
7/19/2022
7/11/2022
current query is returning all rows DATE <= GETDATE()+1
so it would be returning all dates <=7/9/2022 when it actually needs to be <=7/11/22. This being this column never has a date that falls on a weekend or holiday. So on days like Fridays, the query should be trying to pull all rows <= to that coming Monday (the next date in the column or work day). This query has multiple where conditions as well.
WHERE (_Header.CODE IN ('10', '15')) AND (_Header.LOCATION = '89') AND (_Header.OR_NO > '0') AND (_Header.DATE <= GETDATE()+1)

This would give you the next day in a date field after today. It is a simple common table expression you could use in your query. You would just request all dates be <= to the date that is retrieved from the cte.
with cte(nextDay)
AS (SELECT TOP 1 cal_date FROM calendar
WHERE cal_date > GETDATE()
ORDER BY cal_date)
SELECT * FROM cte

Related

prestosql get average from last 7 days for each day

The question I have is very similar to the question here, but I am using Presto SQL (on aws athena) and couldn't find information on loops in presto.
To reiterate the issue, I want the query that:
Given table that contains: Day, Number of Items for this Day
I want: Day, Average Items for Last 7 Days before "Day"
So if I have a table that has data from Dec 25th to Jan 25th, my output table should have data from Jan 1st to Jan 25th. And for each day from Jan 1-25th, it will be the average number of items from last 7 days.
Is it possible to do this with presto?
maybe you can try this one
calendar Common Table Expression (CTE) is used to generate dates between two dates range.
with calendar as (
select date_generated
from (
values (sequence(date'2021-12-25', date'2022-01-25', interval '1' day))
) as t1(date_array)
cross join unnest(date_array) as t2(date_generated)),
temp CTE is basically used to make a date group which contains last 7 days for each date group.
temp as (select c1.date_generated as date_groups
, format_datetime(c2.date_generated, 'yyyy-MM-dd') as dates
from calendar c1, calendar c2
where c2.date_generated between c1.date_generated - interval '6' day and c1.date_generated
and c1.date_generated >= date'2021-12-25' + interval '6' day)
Output for this part:
date_groups
dates
2022-01-01
2021-12-26
2022-01-01
2021-12-27
2022-01-01
2021-12-28
2022-01-01
2021-12-29
2022-01-01
2021-12-30
2022-01-01
2021-12-31
2022-01-01
2022-01-01
last part is joining day column from your table with each date and then group it by the date group
select temp.date_groups as day
, avg(your_table.num_of_items) avg_last_7_days
from your_table
join temp on your_table.day = temp.dates
group by 1
You want a running average (AVG OVER)
select
day, amount,
avg(amount) over (order by day rows between 6 preceding and current row) as avg_amount
from mytable
order by day
offset 6;
I tried many different variations of getting the "running average" (which I now know is what I was looking for thanks to Thorsten's answer), but couldn't get the output I wanted exactly with my other columns (that weren't included in my original question) in the table, but this ended up working:
SELECT day, <other columns>, avg(amount) OVER (
PARTITION BY <other columns>
ORDER BY date(day) ASC
ROWS 6 PRECEDING) as avg_7_days_amount FROM table ORDER BY date(day) ASC

T-sql count number of times a week on rows with date interval

If you have table like this:
Name
Data type
UserID
INT
StartDate
DATETIME
EndDate
DATETIME
With data like this:
UserID
StartDate
EndDate
21
2021-01-02 00:00:00
2021-01-02 23:59:59
21
2021-01-03 00:00:00
2021-01-04 15:42:00
24
2021-01-02 00:00:00
2021-01-06 23:59:59
And you want to calculate number of users that is represented on each day in a week with a result like this:
Year
Week
NumberOfTimes
2021
1
8
2021
2
10
2021
3
4
Basically I want to to a Select like this:
SELECT YEAR(dateColumn) AS yearname, WEEK(dateColumn)as week name, COUNT(somecolumen)
GROUP BY YEAR(dateColumn) WEEK(dateColumn)
The problem I have is the start and end date if the date goes over several days I want it to counted each day. Preferably I don't want the same user counted twice each day. There are millions of rows that are constantly being deleted and added so speed is key.
The database is MS-SQL 2019
I would suggest a recursive CTE:
with cte as (
select userid, startdate, enddate
from t
union all
select userid, startdate,
enddate
from cte
where startdate < enddate and
week(startdate) <> week(enddate)
)
select year(startdate), week(startdate), count(*)
from cte
group by year(startdate), week(startdate)
option (maxrecursion 0);
The CTE expands the data by adding 7 days to each row. This should be one day per week.
There is a little logic in the second part to handle the situation where the enddate ends in the same week as the last start date. The above solution assumes that the dates are all in the same year -- which seems quite reasonable given the sample data. There are other ways to prevent this problem.
You need to cross-join each row with the relevant dates.
Create a calendar table with columns of years and weeks, include a start and end date of the week. See here for an example of how to create one, and make sure you index those columns.
Then you can cross-join like this
SELECT
YEAR(dateColumn) AS yearname,
WEEK(dateColumn)as weekname,
COUNT(somecolumen)
FROM Table t
JOIN CalendarWeek c ON c.StartDate >= t.StartDate AND c.EndDate <= t.EndDate
GROUP BY YEAR(dateColumn), WEEK(dateColumn)

SQL Server aggregation the latest 12 months

Suppose I have the following table:
Id Visitors Date
------------------------------
1 100 '2017-01-01'
2 200 '2017-01-02'
3 150 '2017-01-03'
I want a query to provide the average of a range of records for the last 12 months.
For one record I know that it would be like :
select avg(Visitors), Date
from Visitors_table
where Date between '2018-01-01' and '2017-01-01'
However, I need to do that for a range of dates and multiple records.
I know that Union will solve it, but if the range is one year for example It is not optimized to use 365 union
Get the dates from 1 year ago to current date:
SELECT
Date,
AVG(Visitors) AS avgvisitors,
FROM Visitors_table
WHERE Date > dateadd(year, -1, getdate())
GROUP BY Date
ORDER BY Date;
Since you need to group by date.

Retrieve records between a current date and previous date

I need to get a count of the # of rows resulting from a query which needs to have the below logic:
Assume the table includes 3 columns for now; ID, VALUE and INSERT DATE
Records inserted on
Current day-1
Minus
records inserted on
the latest business day prior to the (current day-1)
To add more details:
****I am looking for 'number of records' inserted between 2 dates i.e. if 200 records were inserted between Thursday and Friday then when I run the query on Monday my result should show me '200 records'.
Assumption: Business days = Mon-Fri
USE DATEADD Function:
Select
*
FROM
TableName
WHERE CreatedDate Between CAST(DATEADD(d,-1,GETDATE() AS Date) AND CAST( GETDATE() AS Date)
Please try this
Select * FROM TableName WHERE AddedDate Between DATEADD(day,-1,GETDATE()) and GETDATE()

Return just the last day of each month with SQL

I have a table that contains multiple records for each day of the month, over a number of years. Can someone help me out in writing a query that will only return the last day of each month.
SQL Server (other DBMS will work the same or very similarly):
SELECT
*
FROM
YourTable
WHERE
DateField IN (
SELECT MAX(DateField)
FROM YourTable
GROUP BY MONTH(DateField), YEAR(DateField)
)
An index on DateField is helpful here.
PS: If your DateField contains time values, the above will give you the very last record of every month, not the last day's worth of records. In this case use a method to reduce a datetime to its date value before doing the comparison, for example this one.
The easiest way I could find to identify if a date field in the table is the end of the month, is simply adding one day and checking if that day is 1.
where DAY(DATEADD(day, 1, AsOfDate)) = 1
If you use that as your condition (assuming AsOfDate is the date field you are looking for), then it will only returns records where AsOfDate is the last day of the month.
Use the EOMONTH() function if it's available to you (E.g. SQL Server). It returns the last date in a month given a date.
select distinct
Date
from DateTable
Where Date = EOMONTH(Date)
Or, you can use some date math.
select distinct
Date
from DateTable
where Date = DATEADD(MONTH, DATEDIFF(MONTH, -1, Date)-1, -1)
In SQL Server, this is how I usually get to the last day of the month relative to an arbitrary point in time:
select dateadd(day,-day(dateadd(month,1,current_timestamp)) , dateadd(month,1,current_timestamp) )
In a nutshell:
From your reference point-in-time,
Add 1 month,
Then, from the resulting value, subtract its day-of-the-month in days.
Voila! You've the the last day of the month containing your reference point in time.
Getting the 1st day of the month is simpler:
select dateadd(day,-(day(current_timestamp)-1),current_timestamp)
From your reference point-in-time,
subtract (in days), 1 less than the current day-of-the-month component.
Stripping off/normalizing the extraneous time component is left as an exercise for the reader.
A simple way to get the last day of month is to get the first day of the next month and subtract 1.
This should work on Oracle DB
select distinct last_day(trunc(sysdate - rownum)) dt
from dual
connect by rownum < 430
order by 1
I did the following and it worked out great. I also wanted the Maximum Date for the Current Month. Here is what I my output is. Notice the last date for July which is 24th. I pulled it on 7/24/2017, hence the result
Year Month KPI_Date
2017 4 2017-04-28
2017 5 2017-05-31
2017 6 2017-06-30
2017 7 2017-07-24
SELECT B.Year ,
B.Month ,
MAX(DateField) KPI_Date
FROM Table A
INNER JOIN ( SELECT DISTINCT
YEAR(EOMONTH(DateField)) year ,
MONTH(EOMONTH(DateField)) month
FROM Table
) B ON YEAR(A.DateField) = B.year
AND MONTH(A.DateField) = B.Month
GROUP BY B.Year ,
B.Month
SELECT * FROM YourTableName WHERE anyfilter
AND "DATE" IN (SELECT MAX(NameofDATE_Column) FROM YourTableName WHERE
anyfilter GROUP BY
TO_CHAR(NameofDATE_Column,'MONTH'),TO_CHAR(NameofDATE_Column,'YYYY'));
Note: this answer does apply for Oracle DB
Here's how I just solved this. day_date is the date field, calendar is the table that holds the dates.
SELECT cast(datepart(year, day_date) AS VARCHAR)
+ '-'
+ cast(datepart(month, day_date) AS VARCHAR)
+ '-'
+ cast(max(DATEPART(day, day_date)) AS VARCHAR) 'DATE'
FROM calendar
GROUP BY datepart(year, day_date)
,datepart(month, day_date)
ORDER BY 1