how to concatenate Date & Year into one column sql - sql-server-2008

i have Date in one column & year in column and i need to concatenate and get the answer as Jan-2017 and that should be in actual Month oder

SELECT CONCAT(column1, ',', column2) AS Date,
FROM table;

This is simple. I assume your both column data types are DateTime or Date. Try the following:
SELECT CONCAT(SUBSTRING(DATENAME(month, YourMonthColumn), 0,4), '-', Year(YourYearColumn))
FROM YourTableName

Sql Server 2008 compatible: (no concat() and no format())
Using a convert() style of 106 (or 113), and just taking the mon yyyy part, and replacing the ' ' with '-',
and using dates truncated to the month, so we can group and order by it using dateadd(month, datediff(month, 0, [Date] ),0):
select MonthYear = replace(stuff(convert(varchar(12)
,dateadd(month, datediff(month, 0, [Date]), 0)
,106),1,3,''),' ','-')
, Days = count(*)
from dates
group by dateadd(month, datediff(month, 0, [Date]), 0)
order by dateadd(month, datediff(month, 0, [Date]), 0)
rextester demo: http://rextester.com/DFF74396
returns:
+-----------+------+
| MonthYear | Days |
+-----------+------+
| Dec-2016 | 31 |
| Jan-2017 | 31 |
| Feb-2017 | 28 |
| Mar-2017 | 10 |
+-----------+------+
Alternate using datename(month,date) for the month and concatenating the year:
select MonthYear = left(datename(month,dateadd(month, datediff(month, 0, [Date]), 0)),3)
+ '-'
+ convert(char(4),year(dateadd(month, datediff(month, 0, [Date]), 0)))
, Days = count(*)
from dates
group by dateadd(month, datediff(month, 0, [Date]), 0)
order by dateadd(month, datediff(month, 0, [Date]), 0)

Related

Simplify query to make TIMESTAMP column

I have a table with columns of 'year', 'month', 'day', 'hour' and 'minute' separately.
All columns INTEGER except 'month' (VARCHAR) and I added a new column to put everything together, 'date_time' (TIMESTAMP).
+------+-------+------+------+--------+-----------+
| year | month | day | hour | minute | date_time |
+------+-------+------+------+--------+-----------+
| 1987 | 12 | 15 | 9 | 25 | <NULL> |
| 1997 | 10 | 10 | 10 | 40 | <NULL> |
| 1994 | 08 | 9 | 6 | 30 | <NULL> |
+------+-------+------+------+--------+-----------+
I made a query to fill the 'date_time' column like this:
UPDATE dates
SET date_time =
COALESCE(
STR_TO_DATE(
CASE WHEN
CONCAT(
year,
'-',
CASE WHEN LPAD(month, 2, 0) BETWEEN 1 AND 12 THEN LPAD(month, 2, 0) ELSE NULL END,
'-',
CASE WHEN LPAD(day, 2, 0) BETWEEN 1 AND 31 THEN LPAD(day, 2, 0) ELSE NULL END,
' ',
CASE WHEN LPAD(hour, 2, 0) BETWEEN 0 AND 23 THEN LPAD(hour, 2, 0) ELSE NULL END,
':',
CASE WHEN LPAD(minute, 2, 0) BETWEEN 0 AND 59 THEN LPAD(minute, 2, 0) ELSE NULL END,
':00'
)
LIKE '%NULL%' THEN NULL
ELSE
CONCAT(
year,
'-',
CASE WHEN LPAD(month, 2, 0) BETWEEN 1 AND 12 THEN LPAD(month, 2, 0) ELSE NULL END,
'-',
CASE WHEN LPAD(day, 2, 0) BETWEEN 1 AND 31 THEN LPAD(day, 2, 0) ELSE NULL END,
' ',
CASE WHEN LPAD(hour, 2, 0) BETWEEN 0 AND 23 THEN LPAD(hour, 2, 0) ELSE NULL END,
':',
CASE WHEN LPAD(minute, 2, 0) BETWEEN 0 AND 59 THEN LPAD(minute, 2, 0) ELSE NULL END,
':00'
)
END,
'%Y-%m-%d %H:%i:%s'
),
'0000-00-00 00:00:00'
);
It worked but...
My question is if there's a simpler way to write a query to do the same thing.
Putting a number or string in the "YYYYMMDD" format in the DATE() function results in a DATE.
And the MAKETIME() function accepts hours, minutes and seconds to return a TIME.
Then when you concat a DATE and a TIME with a space in between, the resulting string can be put in a DATETIME or TIMESTAMP.
UPDATE dates
SET date_time = CONCAT(DATE(year*10000 + month*100 + day),' ',MAKETIME(hour,minute,0));
A test on db<>fiddle here
You can use STR_TO_DATE to convert a string into a datetime. The second argument is a format specifier, that you can use to describe the format of your input data. There are format specifiers available for some of your use cases, such as :
%c : Month in numeric e.g., 1, 2, 3…12
%e : Day of the month without leading zeros e.g., 1,2,…31
%k : Hour in 24-hour format without leading zero e.g., 0,1,2…23
I cannot see a format specifier for "minutes without leading zeros" and "seconds without leading zeros", but it does not seem to cause issue for MySQL to process them (I tested on MySQL 8.0).
So I guess that you could do :
UPDATE dates
SET datetime = STR_TO_DATE(
CONCAT(year, '-', month, '-', day, ' ', hour, ':', minute, ':', second),
'%Y-%c-%e %k:%i:%s'
)

Getting the month to show date name rather than number when pulling each month in the year

I am pulling data that lists each month of the year but the month column states the first day of each year, how can I make this show the full month name?
Here is some of what I have. I read similar questions and tried to add in what it stated everywhere but I couldn't get it work, help?
SELECT a.MonthDate
,Sum(a.ScrapPcs) / (Sum(a.GrossPcs)*1.00) As ScrapPct
,0.05 As ScrapTarget
,sum (a.GrossPcs) As 'Total Parts Cast'
,sum (a.ScrapPcs) as 'Total Parts Scrap'
,CASE
WHEN Sum(a.ScrapPcs) / (Sum(a.GrossPcs)*1.00) <= 0.05 THEN 1
WHEN Sum(a.ScrapPcs) / (Sum(a.GrossPcs)*1.00) >= 0.9*.05 THEN -1
ELSE 0
END
AS Status
FROM
(
SELECT DATEADD(month, DATEDIFF(month, 0, b.CreationProdDate), 0) As MonthDate
,Count(b.BOOKING_ID) As ScrapPcs
, 0 As GrossPcs
FROM dbo.CPC_BOOKING b
WHERE b.CreationProdDate Between DATEADD(yy, DATEDIFF(yy, 0, GetDate()), 0) AND DateAdd("d", -1, GetDate())
and CPC_BookingTyp_ID in (2,8)
and ManufacturingPlant in (90002604,90017699, 90017705)
GROUP BY DATEADD(month, DATEDIFF(month, 0, b.CreationProdDate), 0)
UNION ALL
SELECT DATEADD(month, DATEDIFF(month, 0, n.ProductionDate), 0) As MonthDate
,0 As ScrapPcs
,Sum(n.Quantity) As GrossPcs
FROM [NORIS].[dbo].[MDL_Data_Ultimate] n
WHERE n.ProductionDate Between DATEADD(yy, DATEDIFF(yy, 0, GetDate()), 0) AND DateAdd("d", -1, GetDate())
and n.ManufacturingPlantGroup = 1
GROUP BY DATEADD(month, DATEDIFF(month, 0, n.ProductionDate), 0)
) a
group by a.MonthDate
Thanks in advance, anything helps
For MySQL:
https://www.w3resource.com/mysql/date-and-time-functions/mysql-monthname-function.php
Use the MONTHNAME function as per the example on that webpage.
SELECT MONTHNAME(a.MonthDate)
For MS SQL Server:
If you want the month name use this in the derived table:
SELECT datename(month,DATEADD(month, DATEDIFF(month, 0, b.CreationProdDate), 0)) As MonthDate
That is, you want to apply the datename(month, date)function to the first column of both unioned queries.

Calculate number of days between 2 dates, then sum and group by month

I'm querying a view that gives me data about multiple hospital patient episodes. It includes two columns that give me the start date of an episode, and an end date.
What I'm attempting to do (bed stay calculations, for anyone NHS) is calculate how many days fall between the 2 dates (easy), but then group the day count by the month it falls in.
e.g. if Startdate = 17th November 2016, and Enddate = 3rd Jan 2017, I'm after an output along the lines of:
Year | Month | No. Bed Days |
-----------------------------
2016 | 11 | 13 |
2016 | 12 | 31 |
2017 | 1 | 3 |
I've got some code that kind of works along the lines I'm after, based on inputting date parameters:
declare #dtFrom date
declare #dtTo date
select #dtFrom = '2016-11-17'
,#dtTo = '2017-01-03'
select year(dt) [Year], month(dt) [Month], count(*) 'No. Bed Days'
from (select top(datediff(d, #dtFrom, #dtTo)) dateadd(d, row_number() over (order by (select null)), #dtFrom) dt
from sys.columns) q
group by year(dt), month(dt)
order by [Year], [Month]
However, because the data contains hundreds of episodes and I want to calculate and sum the bed days for all of these into the single table, rather than supplying date parameters, I want to point the code to the view Inpatients.vw_IP_Episodes and use the following variables to supply the parameters from the data: Episode_Start_Date Episode_End_Date.
I've tried modifying the code to declare the variable names as the parameters, and tried modifying the code to point to the view (as below), but I'm just getting syntax errors.
Please can anyone advise on how to correctly formulate the syntax?
select year(dt) [Year], month(dt) [Month], count(*) 'No. Bed Days'
from Inpatients.vw_IP_Episodes
where
(select top(datediff(d, Episode_Start_Date, Episode_End_Date)) dateadd(d, row_number() over (order by (select null)), Episode_Start_Date) dt
from sys.columns) q
group by year(dt), month(dt)
order by [Year], [Month]
I you you want to generate days between tow dates, Please check approach below
declare #dtFrom date = '2016-11-17'
declare #dtTo date = '2017-01-03'
select year(RowN) as [Year],
Month(RowN) as [Month],
count(*) as [No of Bed Days] from (
select top(datediff(day, #dtfrom, #dtto)+1) RowN = dateadd(day, ( row_number() over(order by (select null)) - 1), #dtFrom)
from master..spt_values s1, master..spt_values s2
) a
group by year(a.RowN), Month(a.RowN)
Output:
+------+-------+----------------+
| Year | Month | No of Bed Days |
+------+-------+----------------+
| 2017 | 1 | 3 |
| 2016 | 11 | 14 |
| 2016 | 12 | 31 |
+------+-------+----------------+
I think my query considers first day as well and if you do not require that you can change accordingly. Also you can do cross apply to your table if you have start and end dates in different table. But Ideal performance scenario is to have date dimension like generated table and do join to that is the faster approach.
I changed your query as below using cross-apply
select year(dt) [Year], month(dt) [Month], count(*) 'No. Bed Days'
from Inpatients.vw_IP_Episodes
cross apply
(
select top(datediff(day, fromdatefromyourtable, todatefromyourtable)+1) dt = dateadd(day, ( row_number() over(order by (select null)) - 1), fromdatefromyourtable) from master..spt_values s1, master..spt_values s2
) q
group by year(dt), month(dt)
order by [Year], [Month]
You need to replace fromdatefromyourtable - to fromdate column of your table and todatefromyourtable - to todate column from your table.
I am not clear when you say this part: 'However, because the data contains hundreds of episodes and I want to calculate and sum the bed days for all of these into the single table, rather than supplying date parameters, I want to point the code to the view Inpatients.vw_IP_Episodes and use the following variables to supply the parameters from the data: Episode_Start_Date Episode_End_Date.' what you mean. We cannot see your table structures unless you present them. So does it self contain everything you need and you just want to present on top of that? I can give a self extracting example of how I would do this problem. I tend to not favor doing the group by (metric1), (metric2), etc when it is a date. I like to do the sql syntax trick of:
DateAdd((precision), DateDiff(Precision), 0, (yourDateField), 0)
This essentially does all the grouping in one shot for you and is in a DateTime format already. I would do the groupings like so:
--Add Some test data
DECLARE #Dates TABLE (Id INT IDENTITY, Dt DATETIME)
DECLARE
#StartD DATE = '2016-8-1'
, #EndD DATE = '2017-5-1'
;
SET NOCOUNT ON;
WHILE #StartD <= #EndD
BEGIN
INSERT INTO #Dates (Dt)
VALUES (#StartD)
SELECT #StartD = DATEADD(DAY, 1, #StartD)
END
DECLARE
#Start DateTime = '2016-8-21'
, #End DateTime = '2017-4-10'
;
SELECT
DATEADD(MONTH, DATEDIFF(MONTH, 0, Dt), 0)
, COUNT(*) AS DayCount
From #Dates
WHERE Dt BETWEEN #Start AND #End
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Dt), 0)
SELECT
#Start = '2016-10-25'
, #End = '2017-4-2'
;
SELECT
DATEADD(MONTH, DATEDIFF(MONTH, 0, Dt), 0)
, COUNT(*) AS DayCount
From #Dates
WHERE Dt BETWEEN #Start AND #End
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Dt), 0)
--If I simply want to have another table do the join that's not hard
DECLARE #Temp TABLE (St DATETIME, Ed DATETIME);
INSERT INTO #Temp VALUES ('2016-12-8', '2017-2-7')
SELECT
DATEADD(MONTH, DATEDIFF(MONTH, 0, Dt), 0)
, COUNT(*) AS DayCount
From dbo.SomeData
WHERE Dt BETWEEN (SELECT MIN(St) FROM #Temp) AND (SELECT MAX(Ed) FROM #Temp)
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Dt), 0)
With thanks to #Kannan_Kandasamy, the solution was obtained by combining a cross apply approach to the original query, as below:
select year(dt) [Year], month(dt) [Month], count(*) 'No. Bed Days'
from Inpatients.vw_IP_Episodes
cross apply
(
select top(datediff(day, Episode_Start_Date, Episode_End_Date)) dateadd(d, row_number() over (order by (select null)), Episode_Start_Date) dt
from sys.columns) q
group by year(dt), month(dt)
order by [Year], [Month]

MySQL: Select with first and last day of previous month

Using PhpMyadmin, I have this sentence working:
SELECT id_order as Ref FROM t_orders WHERE DATE(invoice_date) = CURDATE()
Now I want to reemplace "current date" (CURDATE) for the first day of previous month in advance.
The answer of Ankit Bajpai solved my problem (thank you):
SELECT id_order as Ref FROM t_orders WHERE DATE(invoice_date) >= concat(date_format(LAST_DAY(now() - interval 1 month),'%Y-%m-'),'01');
in MYSQL you can try the below
First day of Previous Month
select last_day(curdate() - interval 2 month) + interval 1 day
Last day of Previous Month
select last_day(curdate() - interval 1 month)
First day of Current Month
select last_day(curdate() - interval 1 month) + interval 1 day
Last day of Current Month
select last_day(curdate())
Try following query:-
SELECT id_order as Ref
FROM t_orders
WHERE DATE(invoice_date) >= concat(date_format(LAST_DAY(now() - interval 1 month),'%Y-%m-'),'01');
For MS SQL Server:
DECLARE #firstDayOfLastMonth DATETIME = DATEADD(MONTH, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
DECLARE #lastDayOfLastMonth DATETIME = DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
SELECT #firstDayOfLastMonth;
SELECT #lastDayOfLastMonth;
After reading closely... you want the entire month, of the previous month. You can do this:
SELECT id_order as Ref FROM t_orders
WHERE
DATE(invoice_date) >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0)
AND
DATE(invoice_date) <= DATEADD(month, DATEDIFF(MONTH, 0, GETDATE()), -1)
OR
SELECT id_order as Ref FROM t_orders
WHERE
MONTH(DATE(invoice_date)) = MONTH(DATEADD(MONTH,-1,GETDATE()))

i want to calculate sum of leaverequested column month wise

empid leavefrom leaveto leaverequested
1 3/3/2014 4/3/2014 2
1 7/3/2014 8/3/2014 2
1 31/3/2014 1/4/2014 2
1 10/4/2014 11/4/2014 2
I want to calculate the sum of the leaverequested column.
Ouput:
march - 5 days
april - 3 days
This is my SQL query so far:
select Emp_id
,datename(month,leave_from) as [First]
,datename(month,leave_to) as Last
,count(DATEDIFF(Day, leave_from, leave_to)+1) as [Total Leave]
,sum(DATEDIFF(Day, leave_from, leave_to)+1) as [Total Days]
from emp_leave
group by Emp_id
,datename(month,leave_from)
,datename(month,leave_to);
Can any one help me to get this output please?
One way to go about it
WITH n AS
(
SELECT 0 n
UNION ALL
SELECT n + 1 FROM n WHERE n < 32 -- adjust as needed to max months that a leave can possibly span
), base AS
(
SELECT empid,
DATEADD(mm, n.n, DATEADD(mm, DATEDIFF(mm, 0, leavefrom), 0)) basemonth,
CASE WHEN leavefrom > DATEADD(mm, n.n, DATEADD(mm, DATEDIFF(mm, 0, leavefrom), 0))
THEN leavefrom
ELSE DATEADD(mm, n.n, DATEADD(mm, DATEDIFF(mm, 0, leavefrom), 0))
END sdate,
CASE WHEN leaveto < DATEADD(mm, n.n, DATEADD(mm, DATEDIFF(mm, 0, leavefrom) + 1, -1))
THEN leaveto
ELSE DATEADD(mm, n.n, DATEADD(mm, DATEDIFF(mm, 0, leavefrom) + 1, -1))
END edate
FROM emp_leave JOIN n
ON n.n <= DATEDIFF(month, leavefrom, leaveto)
)
SELECT empid,
YEAR(basemonth) year,
DATENAME(mm, basemonth) month,
SUM(DATEDIFF(dd, sdate, edate) + 1) total
FROM base
GROUP BY empid, basemonth
ORDER BY empid, base month
Output:
| EMPID | YEAR | MONTH | TOTAL |
|-------|------|-------|-------|
| 1 | 2014 | March | 5 |
| 1 | 2014 | April | 3 |
Here is SQLFiddle demo