How to get unique dates based on from_date and to_date in SQL Server - sql

from_date to_date duration
-------------------------------------
2018-10-01 2018-10-10 9
2018-10-05 2018-10-07 3
If I provide input #from_date = 2018-10-01, to_date = 2018-10-11, I want to display count as 9

How about that:
SELECT DATEDIFF(DAY,'20181001','20181011')-1

--To select a single value per row
SELECT
DATEDIFF(DAY,from_date,to_date) as duration
FROM
SomeTable
You could apply a WHERE clause to filter to just a specific row that you want the duration of returned or wrap the DATEDIFF function in an AVG() or SUM() to get the avergae or total of all the durations in the table. You can do all kinds of very complex things with T-SQL. For instance the below query will get you the average duration for each month when whatever was started (from_date) for the year 2017.
E.G. -
SELECT
DATEPART(Month, from_date) as Month,
AVG(DATEDIFF(DAY, from_date, to_date) as AvgDuration
FROM SomeTable
WHERE
DATEPART(Year, from_date) = 2017
GROUP BY
DATEPART(Month, from_date)
Hope this helps. If not, feel free to try again. :)

Related

SQL No of count month wise

I have a data set as below,
data is basically year and month YYYYMM, I need to bring a count of months eg 202001 is appearing 3 times, hence the count should be Nov 3 ( Desired output is shared below )
I'm unable to start to bring out the desired output, help would be much appreciated.
(Temp tables are not allowed to be created in the servers)
Please find the link for sample data link
Help would be much appretiated.
You can use to_date() to convert your number to a proper date, then group by that date:
select to_date(due_date_key::text, 'yyyymm') as due_date,
count(*)
from t
group by due_date;
The "due_date" column is a proper date, you can use the to_char() function to format it differently:
select to_char(due_date, 'yyyy') as year,
to_char(due_date, 'Mon') as output,
count
from (
select to_date(due_date_key::text, 'yyyymm') as due_date,
count(*)
from t
group by due_date
) t
order by due_date;
Online example

SQL - MAX GROUP BY, Include Additional Column [duplicate]

This question already has answers here:
Get top 1 row of each group
(19 answers)
How to select a max row for each group in SQL
(3 answers)
Closed 1 year ago.
I have a table of purchases in the following format (simplified):
tDate
tAmount
tDesription
2021-01-01
1.50
Ice Cream
2021-01-01
1.60
Pencils
2021-02-03
4.50
Paper
2021-02-04
2.50
Staples
I'm trying to find the MAX() value of a purchase for each month, simple enough, but I can't seem to include additional columns in the result set from the row selected as the max. The output I'm looking for is:
tDate
tMonth
tYear
tAmount
tDesription
2021-01-01 00:00:00.000
January
2021
1.60
Pencils
2021-02-01 00:00:00.000
February
2021
4.50
Paper
My thoughts where that I would add in a start of the month column for each row, group by that, and apply the MAX() to the amount, along with a date filter, which works, also had to apply the tMonth and tYear in the group by.
What I've tried is:
SELECT DATEADD(MONTH, DATEDIFF(MONTH,0, [tDate]),0), FORMAT([tDate], 'MMMM') as 'Month', FORMAT([tdate], 'yyyy') as 'Year', MAX([tAmount]) as 'tAmount'
-- Source Table
FROM t
-- Last X months
WHERE [tDate] >= DATEADD(month, -6, getDate())
-- Group by the month
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH,0, [tDate]),0), FORMAT([tDate], 'MMMM'), FORMAT([tDate], 'yyyy')
-- Order
ORDER BY DATEADD(MONTH, DATEDIFF(MONTH,0, [tDate]),0) DESC
Which gives me something very close, but as soon as I add the [tDescription] column I'll receive the 'column not included in aggregate or group by' error, and I obviously can't include the column in the group by, otherwise I'll end up with a row for each.
So I'm pretty stuck on the best approach to include the [tDescription] column in the results, and I've a feeling this query is flawed, does anyone have any ideas?
You can use window functions:
select t.*
from (select t.*,
row_number() over (partition by year(date), month(date) order by tAmount desc) as seqnum
from t
) t
where seqnum = 1;
To include the name of the month, you can add datename(month, date). However, that seems redundant with the date column.

SQL Count of date values that dont match hour and day in select statement

I have a problem unique to a business process. My user needs to know how many dates, counted, are before a specific end time that do not match on the hour or the day.
Here is an example.
AAA, 2016-03-15 16:00:28.967, 2016-03-15 16:02:58.487, 2016-03-17 14:01:24.243
In the example above id AAA has 3 entries. I need to count only the ones that don't have a matching hour and day. So the actual count should come out to be 2.
I have to do this all in SQL and can't use a CTE. It needs to be either a sub select or some type of join.
Something like this.
SELECT id, date, (
SELECT COUNT(*)
FROM x
WHERE day!=day
AND hour!=hour AND date < z
) AS DateCount
Results would be AAA, 2
I am thinking some type of recursive comparison but I am not sure how to accomplish this without a CTE.
In SQL Server you can try something like this:
SELECT id, CONVERT(VARCHAR(13), [date], 120) AS [Date], COUNT(*) AS DateCount
FROM YourTable
WHERE [date] < #ENDDATE
GROUP BY id, CONVERT(VARCHAR(13), [date], 120)
SELECT a AS current_a, COUNT(*) AS b,day AS day, hour as hour,
(SELECT COUNT(*)
FROM t
WHERE day != day
AND hour != hour
AND date < z ) as datecount
FROM t GROUP BY a ORDER by b DESC

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)

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