SQL Server ORDER BY when using DATENAME function - sql

SELECT CAST(DATEPART(yyyy,DATE1)
AS varchar (5)) + '-' + CAST(DATENAME(m,ec2.DATE2)
AS varchar(3)) AS [Month],
CAST(AVG(CAST(DATEDIFF(day,DATE1, DATE2)
AS DECIMAL(10,2))) AS DECIMAL(10,2)) AS tt
FROM tbl3
GROUP BY CAST(DATEPART(yyyy,DATE1) AS
varchar (5)) + '-' + CAST(DATENAME(m,ec2.DATE2)
AS varchar(3))
ORDER BY [Month]
So in the above query I have results for 2 different years so its sorting year in integer wise but Month according to alphabets(as its DATENAME)
Examples:
2013-Dec 4.45
2013-Nov 5.55
2014-Jan 2.35
2014-Jan 2-85
The problem is I am using DATE2 in my aggregate function(Avg) and hence can't use it in ORDER BY clause.
Anyone has a solution for this problem. I will be really thankful if you can help me. I read other questions regarding this problem but didn't find the solution.
Thanks in advance.

A convoluted way, but works in any situation. Use CTE to solve your issue as below:
With CTE as (
SELECT CAST(DATEPART(yyyy,DATE1)
AS varchar (5)) + '-' + CAST(DATENAME(m,ec2.DATE2)
AS varchar(3)) AS [Month],
CAST(AVG(CAST(DATEDIFF(day,DATE1, DATE2)
AS DECIMAL(10,2))) AS DECIMAL(10,2)) AS tt
FROM tbl3
GROUP BY CAST(DATEPART(yyyy,DATE1) AS
varchar (5)) + '-' + CAST(DATENAME(m,ec2.DATE2)
AS varchar(3))
Select * from CTE
ORDER BY
DATEPART(yyyy, cast([Month] as datetime)),
DATEPART(mm, cast([Month] as datetime));

I agree you can order by Year/Month as Darius X suggested. You can also use a cross apply to "wrap" your calculation. Not sure it would solve your specfic problem, but for additional information. I figure out the MatchStatus in the CROSS APPLY then use MatchStatus in the SELECT & GROUP BY clauses.
SELECT
MatchStatus,
COUNT(*)
FROM MPI.ACTData.Matches
CROSS APPLY (SELECT CASE WHEN MatchScore >= 69 THEN 'Match'
ELSE 'Review' END MatchStatus) ms
GROUP BY MatchStatus

Related

CONCAT columns without sub-query SQL Server

I was looking to see if there was a better approach to this query
The date field is formatted - 06-03-2018
I need a column that looks like e.g. Mar-18
e.g
SELECT
CONCAT(P.[Month] + '-', p.[Year]) AS [Month-Year]
FROM
(
SELECT
left(datename(MONTH,[Date]),3) AS [Month]
,right(YEAR([Date]),2) AS [Year]
FROM
Table1
)P
This gives me the result i want but i was wondering if there was anyway to get the same result without a sub-query. Thanks
Why not just format the date as
select format(convert(date, '06-03-2018', 103), 'MMM-yy')
The query you've provided isn't valid, you need a comma (,) between column declarations (which you're missing.
Anyway, the query can be simplified to:
SELECT LEFT(DATENAME(MONTH,[Date]),3) + '-' + RIGHT(YEAR([Date]),2) AS [Month-Year]
FROM Table1;
I haven't used CONCAT here, as there is no need (as either both values will be NULL or have a value).
You Can Do the concatenation directly
SELECT
CAST(LEFT(datename(MONTH, [Date]), 3) AS VARCHAR(20))
+'-'+
CAST(RIGHT(YEAR([Date]), 2) AS VARCHAR(20))
FROM Table1;

How to count events based on parsing date - GROUP BY issues

I am attempting to count how many FAILURE events occurred per day, and the events are stored in a MainEventTable with columns of EventDateTime, EventId, and EventStatus. I'm using SQL Server Management Studio 2016, and it didn't recognize the DATEFROMPARTS function. This is the code that I've put together so far:
SELECT
t.EventDate,
SUM(t.EventCount) AS EventCount
FROM (
SELECT
CAST(
(
CAST(
DATEPART(yyyy,s.EventDateTime)
AS VARCHAR(4)
) + '-' +
CAST(
DATEPART(mm,s.EventDateTime)
AS VARCHAR(2)
) + '-' +
CAST(
DATEPART(dd,s.EventDateTime)
AS VARCHAR(2)
)
) AS DATE
) AS EventDate,
Count(s.EventId) AS EventCount
FROM (
SELECT
EventDateTime,
EventId
FROM
MainEventTable WITH(NOLOCK)
WHERE EventDateTime > '2016-12-07 00:00:00'
AND EventStatus = 'FAILURE'
) AS s GROUP BY CAST(
(
CAST(
DATEPART(yyyy,s.EventDateTime)
AS VARCHAR(4)
) + '-' +
CAST(
DATEPART(mm,s.EventDateTime)
AS VARCHAR(2)
) + '-' +
CAST(
DATEPART(dd,s.EventDateTime)
AS VARCHAR(2)
)
) AS VARCHAR(10)
)
) AS t
GROUP BY t.EventDate;
UPDATE: (THANKS to #wrslphil and #PM_77-1 for assistance with my GROUP BY issues) I've fixed my GROUP BY issues above and found that this worked, although it was very clunky. #KeithL simplified it MUCH more below...
Not a lot to go on here, but the query definitely won't run if you have an item that isn't in the group by list or aggregated in your select clause
I would think that you probably need to do a sum of your count field... like so
SELECT
t.EventDate,
SUM(t.EventCount) as EventCount
FROM (
SELECT
CAST(
(
CAST(
DATEPART(yyyy,s.EventDateTime)
AS VARCHAR(4)
) +
CAST(
DATEPART(mm,s.EventDateTime)
AS VARCHAR(2)
) +
CAST(
DATEPART(dd,s.EventDateTime)
AS VARCHAR(2)
)
) AS DATE
) AS EventDate,
Count(s.EventId) As EventCount
FROM (
SELECT
EventDateTime,
EventId
FROM
MainEventTable WITH(NOLOCK)
WHERE EventDateTime > '2016-12-07 00:00:00'
AND EventStatus = 'FAILURE'
) AS s
) AS t
GROUP BY t.EventDate;
The query is still unlikely to run because you have the same issue in your inner query. I would probably just do the transformation of the date within an inner query and encapsulate it with a query containing a count and group by
select CAST(EventDateTime AS DATE),COUNT(*)
FROM MainEventTable
WHERE EventDateTime > '2016-12-07 00:00:00'
AND EventStatus = 'FAILURE'
GROUP BY CAST(EventDateTime AS DATE)
Your sub-query has the following structure:
SELECT field1, COUNT(field2)
FROM theTable
In the same select you use a "raw" field and aggregation (COUNT). You do not have GROUP BY clause.
You are confusing your SQL engine, since it's impossible to figure out what value of field1 should be picked.
If you intention was to count how many records with non-NULL value of field2 each value of field1 has then the code would be:
SELECT field1, COUNT(field2)
FROM theTable
GROUP BY field1

Convert varchar MMDDYYYY to MM/DD/YYYY datetime and select the most recent date only

Okay, so I have kind of a weird issue... the dates in the table have been entered in as string values MMDDYYYY and I'm trying to have the displayed as MM/DD/YYYY in a report and only select the most recent date pertaining to an ID, because some ID's may have multiple dates.
Example of my table:
ID | MyDate |
------+----------+
1 | 01302014 |
1 | 04222014 |
2 | 01302014 |
What I want to see when I select and insert into a temp table is this:
ID | MyDate |
------+-----------+
1 | 4/22/2014 |
2 | 1/30/2014 |
I know that storing dates as string values is a poor practice especially when storing them as MMDDYYYY, but does anyone have a solution to this nightmare?
EDIT
I forgot to mention that some fields might be NULL. Not sure if that makes a difference or not, but I think it does if I try to flip the dates using Right, Left, Convert.
This question is for almost a year ago, nut probably someone can find it useful.
You need to CONVERT your string to DATE format and use a ROW_NUMBER function to window your result set.
Create table
DECLARE #tbl TABLE(Id INT, myDate VARCHAR(8))
Sample data
INSERT #tbl
SELECT 1 , '01302014' UNION ALL
SELECT 1 , '04222014' UNION ALL
SELECT 2 , '01302014'
Query
;WITH C AS(
SELECT ROW_NUMBER() OVER (PARTITION BY Id ORDER BY CONVERT(DATETIME, (SUBSTRING(myDate, 5, 4) + '.' + SUBSTRING(myDate, 1, 2) + '.' + SUBSTRING(myDate, 3, 2)), 101) DESC) AS Rn
,Id
,CAST(CONVERT(DATETIME, (SUBSTRING(myDate, 5, 4) + '.' + SUBSTRING(myDate, 1, 2) + '.' + SUBSTRING(myDate, 3, 2)), 101) AS DATE) AS myDate
FROM #tbl
)
SELECT Id, myDate
FROM C
WHERE Rn = 1
SQLFiddle Demo
Using a CONVERT like the following code snippet will work on any SQL Server regardless of language and/or locale configuration.
DECLARE #OldDate varchar(8);
SELECT #OldDate = '04252012';
SELECT CONVERT(datetime, substring(#OldDate,5,4) + '-' + substring(#OldDate,1,2) + '-' + substring(#OldDate,3,2) + 'T00:00:00')
You could try this:
convert(date,SUBSTRING (MyDate,1,2)+'/'+SUBSTRING (MyDate,3,2)+'/'+SUBSTRING (MyDate,5,4),101)
Select CONVERT(datetime,RIGHT('01302014',4) +
LEFT('01302014',2) +
SUBSTRING('01302014',3,2))
'2014-01-30 00:00:00.000'
;with Cte as (Select Id,CONVERT(datetime,RIGHT(MyDate,4)+LEFT(MyDate,2)+SUBSTRING(MyDate,3,2)) as sDate, C=ROW_NUMBER()
over(PARTITION By Id Order by MyDate desc)
From #Temp)
select *
from Cte
where C=1
First do a conversion to a datetime datatype, then convert it to a format you wish to:
select id, convert(varchar, max(convert(datetime,right(mydate, 4)+left(mydate,4))), 101)
from #t
group by id
Although I can't understand why would it not suffice to just convert it do datetime and leave the formatting where it belongs, to the client.
Select id,convert(varchar(11),cast(dateValue as Date),101)
From
(
Select id,MAX(cast(MyDate As Date)) as dateValue
From tableName
Group By id
) t
The simplest solution is mySQL str_to_date() function.
STR_TO_DATE(`MyDate`, '%m%d%Y')
This will convert it to a DATETIME which you then format as required
DATE_FORMAT(STR_TO_DATE(`MyDate`, '%m%d%Y'), '%c/%e/%Y')
Complete Query:
Select ID, Case When IsDate(RIGHT(MyDate,4)+LEFT(MyDate,2)+SUBSTRING(MyDate,3,2)) = 1
THEN Convert(varchar(10), Convert(datetime, RIGHT(MyDate,4)+LEFT(MyDate,2)+SUBSTRING(MyDate,3,2)), 101)
ELSE Null END AS MyDate FROM YourTable a where Case When IsDate(RIGHT(MyDate,4)+LEFT(MyDate,2)+SUBSTRING(MyDate,3,2)) = 1
THEN Convert(varchar(10), Convert(datetime, RIGHT(MyDate,4)+LEFT(MyDate,2)+SUBSTRING(MyDate,3,2)), 101)
ELSE Null END = (Select Max(Case When IsDate(RIGHT(MyDate,4)+LEFT(MyDate,2)+SUBSTRING(MyDate,3,2)) = 1
THEN Convert(varchar(10), Convert(datetime, RIGHT(MyDate,4)+LEFT(MyDate,2)+SUBSTRING(MyDate,3,2)), 101)
ELSE Null END)
FROM YourTable b
Where a.ID = b.ID
)
This is a modified version from Dimitris Kalaitzis' answer.
First, you will need to convert your MyDate into String. The data for example (01302014) is not treated as a string and the leading zero will be removed when you convert it. Therefore, use CAST to make MyDate as a String and add a leading 0 to it. Then you find the right 8 characters so to get rid of the leading zero for months from Oct to Dec.
Here is the code that should work for you:
CONVERT(Date, SUBSTRING(RIGHT('0' + CAST(MyDate AS VARCHAR(10)), 8), 1, 2) + '/' + SUBSTRING(RIGHT('0' + CAST(MyDate AS VARCHAR(10)), 8), 3, 2) + '/' + SUBSTRING(RIGHT('0' + CAST(MyDate AS VARCHAR(10)), 8), 5, 4), 101)
Hope this helps.
You first have to add the slashes to be able to convert it to a date, use STUFF
Then convert it to a DATE and select the MAX group by ID
Query:
SELECT ID, FORMAT(MAX(CONVERT(DATE,STUFF(STUFF(MyDate,3,0,'/'),6,0,'/'))),'MM/dd/yyyy') AS MyDate FROM TableName
GROUP BY ID

MS SQL distinct function

I have the query below
SELECT distinct
count(patient.id)
CAST(YEAR(completiondate) AS VARCHAR(4)) + '-' + CAST(MONTH(completiondate) AS VARCHAR(2)) AS Mjesec
FROM ....
WHERE
incident.completionDate Between Convert(smalldatetime, '01/10/2007', 103) and Convert(smalldatetime, '01/11/2013', 103)
and servicecharges.serviceid in (47)
and incident.status != 6
and ServiceRequestDescription LIKE 'something'
and chargeDescr = 'test'
group by CAST(YEAR(completiondate) AS VARCHAR(4)) + '-' + CAST(MONTH(completiondate) AS VARCHAR(2))
the result i take, have unique rows of patient.id AND Year-Month. That means that i can have multiple rows with the same patient.id and several year-month.
how can i change that query, in order to take the results, with each patient.id only once, with the first completiondate with the specific elements?
I guess it should be:
SELECT
patient.id
MIN(
CAST(YEAR(completiondate) AS VARCHAR(4)) + '-' + CAST(MONTH(completiondate) AS VARCHAR(2))
)
AS Mjesec
FROM ....
WHERE
incident.completionDate Between Convert(smalldatetime, '01/10/2007', 103) and Convert(smalldatetime, '01/11/2013', 103)
and servicecharges.serviceid in (47)
and incident.status != 6
and ServiceRequestDescription LIKE 'something'
and chargeDescr = 'test'
group by patient.id
Please Try it
WITH CTE AS
(
SELECT *,RN=ROW_NUMBER() OVER (PARTITION BY patient ORDER BY patient DESC) FROM tablename
)
select * from CTE where RN>1

Sum by month in SQL

I am trying to sum my daily data (trunc(DM_OWNER.LD_LEG_DW.CPLD_DTT) by month. This is created in a Web Intelligence BI report.
SELECT
DM_OWNER.LD_LEG_DW.LGST_GRP_CD,
DM_OWNER.LGST_GRP_T.LGSTGRP_DESC,
DM_OWNER.LD_LEG_DW.CARR_CD,
DM_OWNER.LD_LEG_DW.LD_LEG_ID,
DM_OWNER.LD_LEG_DW.BILL_TO_CUST_CD,
trunc(DM_OWNER.LD_LEG_DW.CPLD_DTT),
trunc(DM_OWNER.VCHR_AP_T.CRTD_DTT),
AP_Detail.PYMNT_AMT_DLR
FROM
DM_OWNER.LD_LEG_DW,
DM_OWNER.LGST_GRP_T,
DM_OWNER.VCHR_AP_T,
DM_OWNER.CHRG_DETL_T_NOTOTAL_V AP_Detail
WHERE
( DM_OWNER.LD_LEG_DW.LD_LEG_ID=DM_OWNER.VCHR_AP_T.LD_LEG_ID(+) )
AND ( DM_OWNER.VCHR_AP_T.VCHR_NUM=AP_Detail.VCHR_NUM_AP )
AND ( DM_OWNER.LD_LEG_DW.LGST_GRP_CD=DM_OWNER.LGST_GRP_T.LGST_GRP_CD )
AND
(
DM_OWNER.LD_LEG_DW.LGST_GRP_CD In ( 'PBRK' )
AND
trunc(DM_OWNER.VCHR_AP_T.CRTD_DTT) >= '01-10-2012 00:00:00'
)
Without clear field names, or an explanation of the data structure, this is too vague. But the principle is
select
displayfields,
year(datefield), month(datefield),
sum(valuefield)
from yourtable
group by
displayfields,
year(datefield), month(datefield),
Without getting into the specifics of your query, here's a general approach.
The CAST is nasty, but this has the benefit of giving you an actual DATETIME as a grouper.
SELECT
SUM(Amount) AS MonthTotal,
CAST(CAST(YEAR(DateCollected) AS VARCHAR(4))
+ '/' + CAST(MONTH(DateCollected) AS VARCHAR(2))
+ '/01' AS DATETIME) AS PaymentMonth
FROM
PaymentsReceived
GROUP BY
CAST(CAST(YEAR(DateCollected) AS VARCHAR(4))
+ '/' + CAST(MONTH(DateCollected) AS VARCHAR(2)) + '/01' AS DATETIME)