SQL Server query to get total against each month of a year and return the year and month in date format not the string format - sql

I have a situation in which i have to calculate "Total" for each month of a year and i have to show total for each month of the year while maintaining datetime format of the date.i am writing the following query:
SELECT [DATE_FORMATION], sum(CO) CO, sum(Total_Members) Total_Members
from (
select convert(varchar(7),CAST([DATE_FORMATION] AS DATE),126) as [DATE_FORMATION],
count([CO_ID]) as CO,
sum(convert(int,[TOTAL_MEMBERS])) as Total_Members
from COCores
where cast([DATE_FORMATION] as date) >= Dateadd(Month, Datediff(Month, 0, DATEADD(m, -10, current_timestamp)), 0)
group by [DATE_FORMATION]
) tmp
group by [DATE_FORMATION]
It is giving the accurate answer which i required
but the problem is it generates date in "Varchar" format where as i require it in datetime format so that i can use it further.how can i get this result while keeping the date in datetime format and getting the same result.

Dates have no formats, they are binary values, just like int or decimal or binary. DATE_FORMATION should be a date type, eg date, datetime or datetime2. If the column uses the correct type, the query can be simplified to just :
select
datefromparts(Year(DATE_FORMATION),MONTH(DATE_FORMATION),1) as DATE_FORMATION,
count([CO_ID]) as CO,
sum([TOTAL_MEMBERS]) as Total_Members
from COCores
where
[DATE_FORMATION] as date) >= DATEFROMPARTS(Year(current_timestamp),1,1)
group by
YEAR(DATE_FORMATION),
MONTH(DATE_FORMATION)
DATEFROMPARTS(Year(current_timestamp),1,1) returns the first date of the current year. This is used to return only rows in the current year. The results are grouped by the Year and Month of DATE_FORMATION using the YEAR and MONTH functions. Finally, SELECT returns the first day of each month by using DATEFROMPARTS to generate a date value from the group keys
Queries like this become far easier if you use a Calendar table. A calendar table contains rows for each date eg for 50 years and extra columns for year, month, day, week number, names, etc that can be used to make reporting easier. Calendar tables are heavily indexed, allowing easy querying eg by year, quarter, semester etc.
Assuming DATE_FORMATION is a date, and a Calendar table with date, Year, Month and StartOfMonth columns, you could turn the query into :
select
Calendar.StartOfMonth,
count([CO_ID]) as CO,
sum([TOTAL_MEMBERS]) as Total_Members
from COCores inner join Calendar on DATE_FORMATION=Calendar.date
where
Calendar.Year= Year(current_timestamp)
group by
StartOfMonth
This query would be fast too as it can take advantage of any indexes on Year, Date and StartOfMonth

You can convert all dates to first day of the month like so:
DATEADD(DAY, 1, EOMONTH(DATE_FORMATION, -1))
It produces a DATE. You can use this expression in GROUP BY and in SELECT clause:
SELECT DATEADD(DAY, 1, EOMONTH(DATE_FORMATION, -1)), COUNT(CO_ID) AS CO, SUM(CONVERT(INT, TOTAL_MEMBERS)) AS Total_Members
FROM COCores
WHERE DATE_FORMATION >= -- calculate -10 months
GROUP BY DATEADD(DAY, 1, EOMONTH(DATE_FORMATION, -1))

Related

Matching date with calculated DATEADD date

I am trying to create a table with columns containing the current date, prior year date, and additional column for the total sum revenue as below:
cur_date | py_date | py_rev
I'm trying to compare revenue across any daily period across years. Assume all dates and revenue values are included in the same SQL Server table.
I attempted to use a case statement using [date] = DATEADD(wk,-52,[date]) as the condition to return the appropriate total. The full line code is below:
select
[date] as cur_date,
DATEADD(wk,-52,[date]) py_date,
SUM(case when [date] = DATEADD(wk,-52,[date]) then sum_rev else 0 end) as py_rev
from summary
group by [date]
When running this code the py_date is as expected but py_rev returns 0 as if there is no match. What's most confusing is if I hard code a random date in place of the DATEADD portion then a total is returned. I have also tried CAST to format both date and the DATEADD portion as date with no luck.
Is there something about DATEADD that will not match to other date columns that I'm missing?
If you want the previous years revenue, then lag() is one method. This works assuming that "previous year" means 52 weeks ago and you have records for all dates:
select [date] as cur_date,
dateadd(week, -52, [date]) as py_date,
lag(sum_rev, 52 * 7) over (order by date) as py_rev
from summary;
If you do not have records for all dates, then another approach is needed. You can use a LEFT JOIN:
select s.date, dateadd(week, -52, s.[date]),
sprev.sum_rev as py_rev
from summary s left join
summary sprev
on sprev.date = dateadd(week, -52, s.[date]);

group by year month in postgresql

customer Date location
1 25Jan2018 texas
2 15Jan2018 texas
3 12Feb2018 Boston
4 19Mar2017 Boston.
I am trying to find out count of customers group by yearmon of Date column.Date column is of text data type
eg: In jan2018 ,the count is 2
I would do something like the following:
SELECT
date_part('year', formattedDate) as Year
,date_part('month', formattedDate) as Month
,count(*) as CustomerCountByYearMonth
FROM
(SELECT to_date(Date,'DDMonYYYY') as formattedDate from <table>) as tbl1
GROUP BY
date_part('year', formattedDate)
,date_part('month', formattedDate)
Any additional formatting for dates could be done on the inner query that will allow for adjustments in case some single digit days need to be padded or a month has four letters instead of three etc.
By converting to date type, you can properly order by date type and not alphabetical etc.
Optionally:
SELECT
Year
,Month
,count(*) as CustomerCountByYearMonth
FROM
(SELECT
date_part('year', to_date(Date,'DDMonYYYY')) as Year
,date_part('month', to_date(Date,'DDMonYYYY')) as Month
FROM <table>) as tbl1
GROUP BY
Year
,Month
You shouldn't store dates in a text column...
select substring(Date, length(Date)-6), count(*)
from tablename
group by substring(Date, length(Date)-6)
I thought #Jarlh asked a good question -- what about dates like January 1? Is it 01Jan2019 or 1Jan2019? If it can be either, perhaps a regex would work.
select
substring (date from '\d+(\D{3}\d{4})') as month,
count (distinct customer)
from t
group by month
The 'distinct customer' also presupposes you may have the same customer listed in the same month, but you only want to count it once. If that's not the case, just remove 'distinct.'
And, if you wanted the output in date format:
select
to_date (substring (date from '\d+(\D{3}\d{4})'), 'monyyyy') as month,
count (distinct customer)
from t
group by month
If it is a date column, you can truncate the date:
select date_trunc('month', date) as yyyymm, count(*)
from t
group by yyyymm
order by yyyymm;
I really read that the type was date. For a string, just use string functions:
select substr(date, 3, 7) as mmmyyyy, count(*)
from t
group by mmmyyyy;
Unfortunately, ordering doesn't work in this case. You should really be storing dates using the proper type.

SQL : Get last 3 month data (with only available data in the column), not from current month or today?

Anyone help me out on this scenario. I need to get a last 3 month data from particular column, which is not from current date but only from available date.
Ex :
I have one Table named Shop and column named OrderDate, In OrderDate i have only dates until 30-06-2017, but today's date is 07-02-2018. From this i need to get last 3 months data, which is Jun'17, May'17 and Apr'17.
If data available in till July'17 means i need result Jul'17,Jun'17 & May'17. And so on.
Any can help on this to achieve in SQL ?
Thanks in advance.
I assume that column OrderDate is of date or datetime datatype.
select * from Shop
where OrderDate >
(select dateadd(month, -3, max(OrderDate)) from Shop)
I think the easiest way to get this is to select the largest date in that table and use that to create the filter.
So;
Select *
from table
where date >
Dateadd
('m', -3,
( Select Max (date) from table)
)
Apologies in advance for poor formatting
You will have to find the maximum date in the table and use that:
select s.*
from Shop s,
(select convert(date,
format(
dateadd(MONTH, -3, max(OrderDate)), 'yyyyMM01')
,112) as fromDate from Shop) md
where s.OrderDate >= md.fromDate

Calculate totals of field based on current fiscal year only - SQL

I have seen many examples regarding calculating the sum of fields using the fiscal year, but I can not find one that fits my needs. What I am trying to do is get just the current fiscal year totals for a field using SQL Query. The fields I have is userid, startdate, total_hours, and missed_hours. Here is the query I have so far:
SELECT
userid,
SUM(total_hours) - SUM(missed_hours) AS hours
FROM mytable
GROUP BY userid
This works great, but all I need is the total number of hours for the current fiscal year for each of the userid's. Our fiscal year runs from July to June. I only need the current fiscal year and I need it to start over again this coming July.
Assuming this is SQLServer, try:
SELECT userid, SUM(total_hours) - SUM(missed_hours) AS hours
FROM mytable
WHERE startdate >= cast( cast(year(dateadd(MM,-6,getdate())) as varchar(4)) +
'-07-01' as date ) and
startdate < cast( cast(year(dateadd(MM, 6,getdate())) as varchar(4)) +
'-07-01' as date )
GROUP BY userid
Add a where clause:
FROM mytable
WHERE startdate >= '2011-07-01'
GROUP BY userid
Or with the start of the year dynamically:
where startdate >= dateadd(yy, datepart(yy, getdate())-2001, '2000-07-01')
Maybe something like this:
SELECT
userid,
SUM(total_hours) - SUM(missed_hours) AS hours
FROM
mytable
WHERE
MONTH(startdate) BETWEEN 6 AND 7
AND YEAR(startdate) IN (2011,2012)
GROUP BY userid
For the solution, two additional information is needed
the name of the date column
the vendor type of RDBMS you are using
I supposed your date column is date_col and you are using MySQL
SELECT
userid,
SUM(total_hours) - SUM(missed_hours) AS hours
FROM mytable
WHERE date_col between STR_TO_DATE('01,7,2011','%d,%m,%Y') and STR_TO_DATE('01,7,2010','%d,%m,%Y')
GROUP BY userid

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