sql : calculate the total birthday moth based on month - sql

I want to code a query to calculate the total birthday moth based on month . Here is the sample data . Two person's bithday are April, 1980 .
How to write this query ?
John 02/21/1980
Peter 02/22/1980
Lucy 04/21/1980
------ result -----
01/1980 0
02/1980 2
03/1980 0
04/1980 1
05/1980 0
.....

You can loop for every months like this:
DECLARE #month INT
DECLARE #year INT
DECLARE #result TABLE (MonthYear varchar(7),BirthdaysCount INT)
SET #month = 1
SET #year = 1980
WHILE(#month < 13)
BEGIN
INSERT INTO #result
SELECT (CAST(#month as VARCHAR) + '/' + CAST(#year as VARCHAR)),
COUNT(*)
FROM test
WHERE MONTH(birth) = #month AND YEAR(birth) = #year
SET #month = #month + 1
END
select * from #result
See the fiddle: http://sqlfiddle.com/#!3/20692/2

In MySQL you would do this:
select concat(month(dob), '/', year(dob)) monthYear, count(*) cnt from t
group by monthYear
order by year(dob), month(dob)
However, in order to get the "missing dates" you'll have to generate data, because 01/1980 is not in any table, as far as I can see. Check this answer to see how.

how about this for sql-server
create table #temp
(
name varchar(50),
DOB datetime
)
insert into #temp values ('john', '2/21/1980')
insert into #temp values ('peter', '2/22/1980')
insert into #temp values ('lucy', '4/21/1980')
select convert(varchar(2), MONTH(DOB)) + '/' + Convert(varchar(4), YEAR(DOB)) as [MM/YYYY]
, count(*) as TotalCount
from #temp
group by convert(varchar(2), MONTH(DOB)) + '/' + Convert(varchar(4), YEAR(DOB))
drop table #temp
EDIT - This will get you all records for the dates included in the dates in the table. It will use the Min/Max Date in the table to get the date range, you then use this range to get the count of the birthdays in each month:
create table #temp
(
name varchar(50),
DOB datetime
)
insert into #temp values ('john', '2/21/1980')
insert into #temp values ('peter', '2/22/1980')
insert into #temp values ('lucy', '4/21/1980')
;with cte as
(
select min(DOB) as MinDate, max(DOB) as MaxDate
from #temp
union all
SELECT dateadd(mm, 1, t.MinDate), t.MaxDate
from cte t
where dateadd(mm, 1, t.MinDate) <= t.MaxDate
)
select convert(varchar(2), MONTH(c.MinDate)) + '/' + Convert(varchar(4), YEAR(c.MinDate))
, IsNull(t.TotalCount, 0) as TotalCount
from cte c
LEFT JOIN
(
SELECT convert(varchar(2), MONTH(DOB)) + '/' + Convert(varchar(4), YEAR(DOB)) as [MM/YYYY]
, count(*) as TotalCount
FROM #temp
group by convert(varchar(2), MONTH(DOB)) + '/' + Convert(varchar(4), YEAR(DOB))
) t
on convert(varchar(2), MONTH(C.MinDate)) + '/' + Convert(varchar(4), YEAR(C.MinDate))
= t.[MM/YYYY]
drop table #temp

Related

Need monthly report where I need summation of Qty for each day

I have one table STOCK_REGISTER where I have columns Id, ItmId, Qty, CreatedDate. And there are daily transaction data like item inward, outward and all.
Now I am developing one Monthly Report where I want to display Day wise summation of item qty for whole month. I have written following query to do so.
SELECT CONVERT(Date,CreatedDate) AS CreatedDate,ItmId, SUM(Qty)
FROM STOCK_REGISTER
GROUP BY CONVERT(Date,CreatedDate),ItmId
This query returns correct data but if I am asking for April-2017 data and STOCK_REGISTER don't have any record on 5th April then it's not displaying 5th April at all where I need 0 value in qty for that item in 5th April.
Can you help me out to get this type of data?
Edit :
I have created query which gives all days of any particular month and have applied left join with STOCK_REGISTER, but still not solving my issue.
declare #month int, #year int
set #month = 4
set #year = 2017
SELECT CAST(CAST(#year AS VARCHAR) + '-' + CAST(#Month AS VARCHAR) + '-01' AS DATETIME) + A.Number AS STKFG_CREATED_DATE,
B.STKFG_ITM_ID,
0 AS OPENING_STOCK,
SUM(STKFG_QTY)
FROM master..spt_values A
LEFT JOIN STOCK_REGISTER_FG B
ON CONVERT(DATE,CAST(CAST(#year AS VARCHAR) + '-' + CAST(#Month AS VARCHAR) + '-01' AS DATETIME) + A.Number) = CONVERT(DATE,B.STKFG_CREATED_DATE)
AND C.ITM_ID = B.STKFG_ITM_ID
WHERE type = 'P'
AND (CAST(CAST(#year AS VARCHAR) + '-' + CAST(#Month AS VARCHAR) + '-01' AS DATETIME) + A.Number ) <
DATEADD(mm,1,CAST(CAST(#year AS VARCHAR) + '-' + CAST(#Month AS VARCHAR) + '-01' AS DATETIME) )
AND STKFG_TRAT_ID = 6
GROUP BY A.Number, B.STKFG_ITM_ID
ORDER BY B.STKFG_ITM_ID,CAST(CAST(#year AS VARCHAR) + '-' + CAST(#Month AS VARCHAR) + '-01' AS DATETIME) + A.Number
Thank you for your comments.
I have found one solution which works fine for me.
Here #TEMP_TABLE contains all dates.
SELECT A.CREATED_DATE,B.ITM_NAME,ISNULL(C.STKFG_QTY,0)
FROM #TEMP_TABLE A
CROSS APPLY ITEM_MASTER B
LEFT JOIN ( SELECT CONVERT(DATE,STKFG_CREATED_DATE) AS STKFG_CREATED_DATE, STKFG_ITM_ID, SUM(STKFG_QTY) AS STKFG_QTY
FROM STOCK_REGISTER_FG GROUP BY CONVERT(DATE,STKFG_CREATED_DATE),STKFG_ITM_ID) C
ON CONVERT(DATE,A.CREATED_DATE) = CONVERT(DATE,C.STKFG_CREATED_DATE)
AND B.ITM_ID = C.STKFG_ITM_ID
ORDER BY B.ITM_NAME,A.CREATED_DATE
Try below script. Here #tblData is your actual table name.
declare #tblData table
(id int,datecolumn date)
INSERT INTO #tblData
(id,datecolumn)
SELECT 1,'2010-01-01' UNION ALL
SELECT 3,'2010-01-01' UNION ALL
SELECT 1,'2010-01-03' UNION ALL
SELECT 2,'2010-01-04' UNION ALL
SELECT 1,'2010-01-05' UNION ALL
SELECT 3,'2010-01-06' UNION ALL
SELECT 1,'2010-01-10' UNION ALL
SELECT 1,'2010-01-10' UNION ALL
SELECT 2,'2010-01-11' UNION ALL
SELECT 1,'2010-01-11' UNION ALL
SELECT 2,'2010-01-11' UNION ALL
SELECT 1,'2010-01-12' UNION ALL
SELECT 3,'2010-01-13'
DECLARE #MaxDate DATE,
#MinDate DATE,
#iDate DATE
DECLARE #DateSequence TABLE(
DATE1 DATE
)
SELECT #MaxDate = Convert(DATE,Max(datecolumn)),
#MinDate = Convert(DATE,Min(datecolumn))
FROM #tblData -- Put your month condition
SET #iDate = #MinDate
WHILE (#iDate <= #MaxDate)
BEGIN
INSERT #DateSequence
SELECT #iDate
SET #iDate = Convert(DATE,Dateadd(DAY,1,#iDate))
END
SELECT a.DATE1 ,isnull(sum(b.id),0) as total
FROM #DateSequence a left join #tblData b on a.DATE1=b.datecolumn
group by a.DATE1
Thanks,

T-SQL: calculate age then add character to result

Been stuck on this one for a while now. Let's say I have a Client table like the one here:
Name BirthDayNum BirthMonthNum BirthYearNum
--------------------------------------------------
John 23 12 1965
Jane 4 9 1975
Joe 6 3 1953
Currently I am calculating the age using this syntax: (sorry if it is hard to read)
DATEDIFF(year, CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2))
+ '-' + CAST(client.BirthDayNum AS varchar(2))
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101), GETDATE())
- (CASE WHEN dateadd(YY, DATEDIFF(year, CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2))
+ '-' + CAST(client.BirthDayNum AS varchar(2))
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101), GETDATE()),
CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2))
+ '-' + CAST(client.BirthDayNum AS varchar(2))
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101)) > getdate() THEN 1 ELSE 0 END) AS 'Client Age'
This will give me the age in years. Of course if I want months, I just change the DATEDIFF(year to month. So, what I am trying to do now is this.
Continue to calculate the age, but instead of returning either years or months, I would like to return the age in years and months, but also, concat a 'y' and 'm' within the value as well. Ex. 41y 11m for Jane above.
So basically I am trying to figure out how to add a char to the return value, as well as calculate the remaining months beyond the year calculation.
Any help would be greatly appreciated!
Tired of twisting myself into knots with date calculations, I created a Table-Valued-Function to calculate elapsed time in Years, Months, Days, Hours, Minutes, and Seconds.
Example
Declare #YourTable table (Name varchar(50),BirthDayNum int, BirthMonthNum int, BirthYearNum int)
Insert Into #YourTable values
('John', 23, 12, 1965),
('Jane', 4, 9, 1975),
('Joe', 6, 3, 1953)
Select A.Name
,B.*
,Age = concat(C.Years,'y ',C.Months,'m')
From #YourTable A
Cross Apply (Select DOB = DateFromParts(A.BirthYearNum,A.BirthMonthNum,A.BirthDayNum)) B
Cross Apply [dbo].[udf-Date-Elapsed](B.DOB,GetDate()) C
Returns
Name DOB Age
John 1965-12-23 51y 3m
Jane 1975-09-04 41y 6m
Joe 1953-03-06 64y 0m
The UDF - May look like overkill, but it is very performant
CREATE FUNCTION [dbo].[udf-Date-Elapsed] (#D1 DateTime,#D2 DateTime)
Returns Table
Return (
with cteBN(N) as (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cteRN(R) as (Select Row_Number() Over (Order By (Select NULL))-1 From cteBN a,cteBN b,cteBN c),
cteYY(N,D) as (Select Max(R),Max(DateAdd(YY,R,#D1))From cteRN R Where DateAdd(YY,R,#D1)<=#D2),
cteMM(N,D) as (Select Max(R),Max(DateAdd(MM,R,D)) From (Select Top 12 R From cteRN Order By 1) R, cteYY P Where DateAdd(MM,R,D)<=#D2),
cteDD(N,D) as (Select Max(R),Max(DateAdd(DD,R,D)) From (Select Top 31 R From cteRN Order By 1) R, cteMM P Where DateAdd(DD,R,D)<=#D2),
cteHH(N,D) as (Select Max(R),Max(DateAdd(HH,R,D)) From (Select Top 24 R From cteRN Order By 1) R, cteDD P Where DateAdd(HH,R,D)<=#D2),
cteMI(N,D) as (Select Max(R),Max(DateAdd(MI,R,D)) From (Select Top 60 R From cteRN Order By 1) R, cteHH P Where DateAdd(MI,R,D)<=#D2),
cteSS(N,D) as (Select Max(R),Max(DateAdd(SS,R,D)) From (Select Top 60 R From cteRN Order By 1) R, cteMI P Where DateAdd(SS,R,D)<=#D2)
Select [Years] = cteYY.N
,[Months] = cteMM.N
,[Days] = cteDD.N
,[Hours] = cteHH.N
,[Minutes] = cteMI.N
,[Seconds] = cteSS.N
From cteYY,cteMM,cteDD,cteHH,cteMI,cteSS
)
--Max 1000 years
--Select * from [dbo].[udf-Date-Elapsed] ('1991-09-12 21:00:00.000',GetDate())
Just to Illustrate
The TVF without any secondary string manipulation would return
Select A.Name
,B.*
From #YourTable A
Cross Apply [dbo].[udf-Date-Elapsed](DateFromParts(A.BirthYearNum,A.BirthMonthNum,A.BirthDayNum),GetDate()) B
EDIT - READ ONLY VERSION
Select A.Name
,B.*
,Age = concat(DateDiff(MONTH,B.DOB,GetDate())/12,'y ',DateDiff(MONTH,B.DOB,GetDate()) % 12,'m')
From #YourTable A
Cross Apply (Select DOB = DateFromParts(A.BirthYearNum,A.BirthMonthNum,A.BirthDayNum)) B
Yes it is easier to save as DOB.. But one simple method
select concat( floor(datediff(year, datefromparts(birthyearnum,birthmonthnum,birthdaynum), getdate()))-1, 'y ', datediff(month, datefromparts(birthyearnum,birthmonthnum,birthdaynum), getdate())%12, 'm')
from #yourDates
How age for 1965 is 41y?
Input table:
create table #yourdates(Name varchar(10), BirthdayNum int, BirthMonthNum int, BirthYearNum int)
insert into #yourdates
(Name, BirthdayNum, BirthMonthNum, BirthYearNum) values
('John', 23 , 12 , 1965 )
,('Jane', 4 , 9 , 1975 )
,('Joe ', 6 , 3 , 1953 )
If you are on 2008 or lesser and can't use datefromparts...
declare #table table ([Name] varchar(4), BirthDayNum int, BirthMonthNum int, BirthYearNum int)
insert into #table
values
('John',23,12,1965),
('Jane',4,9,1975),
('Day',30,3,1990)
;with cte as(
select
[Name],
cast(BirthYearNum as varchar(4)) + '/' + cast(BirthMonthNum as varchar(2)) + '/' + cast(BirthDayNum as varchar(2)) as DOB
from
#table)
select
[Name]
,DOB
,datediff(year,DOB,GETDATE()) as Years
,datediff(month,DOB,GETDATE()) %12 as Months
,rtrim(cast(datediff(year,DOB,GETDATE()) as char(2))) + 'y ' + rtrim(cast(datediff(month,DOB,GETDATE()) %12 as char(2))) + 'm' as Age
from cte

SQL Query : How to get date reference of Month And Year Column?

I need a help to change the Month & Year column as Date in Result.
Ex :
Table Name : AA
Month Year
4 2016
5 2015
Result Should Be:
01-04-2016
01-05-2015
I need a SQL query for this? Can any one help me out?
Try like this,
DECLARE #AA TABLE (
Month INT
,Year INT
)
INSERT INTO #AA (
Month
,Year
)
VALUES (
4
,2016
)
,(
5
,2015
)
SELECT convert(DATE, convert(VARCHAR(50), year * 10000 + month * 100 + 01)) AS DATE
FROM #AA
Try this code:
select '01-'+cast([month] as nvarchar) + '-'+cast([Year] as nvarchar)
from YourTable
Assuming int data types:
DECLARE #Month int = 4, #Year int = 2016
SELECT CAST(CAST(#Year * 10000 + #Month * 100 + 01 As char(8)) as date)
Assuming char/varchar data types:
DECLARE #MonthString varchar(2) = 4, #YearString char(4) = 2016
SELECT CAST(#YearString +'-'+ RIGHT('00' + #MonthString, 2) + '-01' as date)
Results in both cases:
2016-04-01 -- (Date data type)
Add square brackets for the reserve keywords:
DECLARE #AA TABLE ([Month] INT, [Year] INT);
INSERT INTO #AA ([Month], [Year]) VALUES
(4, 2016),
(5, 2015);
SELECT '01-' + RIGHT('00' + CAST([MONTH] AS VARCHAR), 2) + '-' + CAST([Year] AS VARCHAR)
FROM #AA
Result:
01-04-2016
01-05-2015
DECLARE #Table1 TABLE
(Month int, Year int)
;
INSERT INTO #Table1
(Month, Year)
VALUES
(4, 2016),
(5, 2015)
;
select '01'+'-'+RIGHT('000'+CAST(Month AS VARCHAR(3)),2)+'-'+CAST(Year AS VARCHAR) from #Table1
Do not do varchar convertions. Use like below
declare #t table([Month] int,[Year] int)
insert into #t
select 4, 2016 union all
select 5, 2015
select dateadd(month,month-1,dateadd(year,[year]-1900,0)) from #t
You can use concat function to acieve this
SELECT CONCAT('01-',year,'-',month) as req_date from tableName
try this:
declare #y varchar(4)='2015'
declare #m varchar(2)='5'
--try_prase is available starting sql 2012
print try_parse('01-'+#m+'-'+#y as datetime using 'en-us')
print convert(datetime,'01-'+#m+'-'+#y,121)

How to sum set of period times in specific format

If I have result set like that :
Work_hour(hh:mm)
10:24
12:59
06:28
where Work_hour is of type varchar
How to sum those hours and minutes with the same format ?
SELECT CAST(FLOOR(TMP1.MINS/60) AS VARCHAR) + ':' + CAST((TMP1.MINS % 60) AS VARCHAR) FROM (
SELECT SUM (CAST(LEFT(time_column, 2) AS INT) * 60 + CAST(RIGHT(time_column, 2) AS INT)) as MINS FROM table1
) AS TMP1
Where time_column is the column in the table and table1 is the name of the table. Example:
create table table1 (
time_column varchar(10)
);
insert into table1 (time_column) values ('12:20'), ('10:40'), ('15:50');
Results in: 38:50
Try this one -
Query:
DECLARE #temp TABLE
(
work_hour CHAR(5)
)
INSERT INTO #temp (work_hour)
VALUES
('10:24'),
('12:59'),
('06:28')
;WITH cte AS
(
SELECT mn = SUM(DATEDIFF(MINUTE, '19000101', CAST('19000101 ' + work_hour AS DATETIME)))
FROM #temp
)
SELECT CAST(FLOOR(mn / 60) AS VARCHAR(5)) + ':' + CAST(mn % 60 AS VARCHAR(2))
FROM cte
Output:
hm
--------
29:51
Update 2:
DECLARE #temp TABLE
(
transtime_out DATETIME
, transtime_in DATETIME
)
INSERT INTO #temp (transtime_out, transtime_in)
VALUES
('2013-05-19 16:40:53.000', '2013-05-19 08:58:07.000'),
('2013-05-19 16:40:53.000', '2013-05-19 08:58:07.000')
SELECT diff = LEFT(CONVERT(VARCHAR(10), CAST(SUM(CAST(a.transtime_out - a.transtime_in AS FLOAT)) AS DATETIME), 108), 5)
FROM #temp a

Pivot In Values with dates?

At the end of my sql, I am using the following code. Is there any way of replacing the fixed strings [2011/07/14], [2011/07/16], etc, to GetDate() value?
PIVOT
(
count([AppointmentsBooked])
FOR [date] IN ([2011/07/14], [2011/07/16], [2011/07/17],[2011/07/18],[2011/07/21])
) as pivottable
Can you try to use BETWEEN and DATEADD in following manner:
DECLARE #dates TABLE(value DateTime)
INSERT INTO #dates VALUES
(GETDATE()),
('2011/07/9'),
('2011/07/17'),
('2011/07/18'),
('2011/07/21')
SELECT value FROM #dates
WHERE value BETWEEN GETDATE() AND DATEADD(day, 5, GETDATE())
You can create a string of all dates which is comma seperated with '[' and ']' before and after each date. assign this string to a string variable (#dates) and use the string spit method to split all dates inside the pivot query.
this question was posted about a year ago. i don't care. i have some code that might be exactly what the OP wanted.... i'm sure he'll never come back and chose an answer but still.... all i want to do is count the records by month with a pivot for a few tables and ultimately compare the number of records for each month for each table. however... in this code there is only one table (rt_taco_15m) but that doesn't matter. i just haven't written the rest to completely fit my needs. but i think it fits the needs of the OP or at least gets him on a good start.... if he truly has been waiting a year on this problem. lol.
if object_id('tempdb..#temp') is not null drop table #temp
if object_id('tempdb..#temp2') is not null drop table #temp2
if object_id('tempdb..#temp3') is not null drop table #temp3
declare #start_date as datetime
set #start_date = cast('1-1-2012' as datetime)
declare #end_date as datetime
set #end_date = cast('9-1-2012' as datetime)
;with cte as (
select #start_date as [start],
dateadd(month, 1, #start_date) as [end]
union all
select dateadd(month, 1, [start]) as [start],
dateadd(month, 1, dateadd(month, 1, [start])) as [end]
from cte
where dateadd(month, 1, [start]) <= #end_date
)
(select 'rt_taco_15m' as table_name,
convert(varchar(10), [start], 101) as [start],
convert(varchar(10), [end], 101) as [end],
datename(month, [start]) as month_name,
cast([start] as integer) as orderby,
count(taco.taco_record_id) as [range_count]
into #temp
from cte
left outer join rt_taco_15m as taco
on taco.period >= cte.[start] and
taco.period < cte.[end]
group by cte.[start], cte.[end])
select table_name as table_name,
convert(varchar(10), getdate(), 101) as [start],
convert(varchar(10), getdate(), 101) as [end],
'Total' as month_name,
cast(dateadd(month,2,#end_date) as integer) as orderby,
range_sum as [range_count]
into #temp2
from (select table_name, sum([range_count]) as range_sum
from #temp group by table_name) as summed_up
select *
into #temp3
from (select * from #temp
union all
select * from #temp2) as x
order by orderby
select * from #temp3
declare #cols nvarchar(2000)
select #cols = stuff(
(select '],[' + month_name
from #temp3
order by orderby
for xml path('') )
, 1, 2, '') + ']'
print #cols
if object_id('tempdb..#temp2') is not null drop table #temp2
declare #query varchar(max)
set #query = N'
select table_name, ' + #cols + N'
from (select table_name, month_name, range_count
from #temp3) p
pivot ( sum(range_count) for month_name in ( '+ #cols +' ) ) as pvt'
execute(#query