Select Distinct date and Count - sql

My sample table structure is:
TestDate
----------------------
2013-03-25 14:26:40.830
2013-03-20 13:37:39.763
2012-09-10 14:55:55.667
2013-03-20 13:33:20.480
And my query is :
SELECT DISTINCT
REPLACE(RIGHT(CONVERT(VARCHAR(20), TestDate, 106), 8), ' ', '-') AS TT
,(SELECT COUNT(*)
FROM Test bp
WHERE
CONVERT(VARCHAR(20), p.TestDate, 6) = CONVERT(VARCHAR(20), bp.TestDate, 6)) AS Posts
FROM Test p
I got a result:
TT Posts
Mar-2013 1
Mar-2013 2
Sep-2012 1
But I want a result:
TT Posts
Mar-2013 3
Sep-2012 1
But I am unable to find my mistake in my query. Thanks.

Are you trying to select the rows and count for each month?
If so - try something like this:
SELECT
YEAR(Testdate), MONTH(Testdate),
COUNT(*) totalPost
FROM
tableName
GROUP BY
YEAR(Testdate), MONTH(Testdate)
Update: if you insist on formatting that inside SQL Server (which I think is the wrong place to do this...) - then use something like this:
SELECT DISTINCT
SUBSTRING(DATENAME(MONTH, TestDate), 1, 3) + '-' + CAST(YEAR(TestDate) AS VARCHAR(4)),
YEAR(Testdate), MONTH(Testdate),
TotalPosts = COUNT(*)
FROM
tableName
GROUP BY
SUBSTRING(DATENAME(MONTH, TestDate), 1, 3) + '-' + CAST(YEAR(TestDate) AS VARCHAR(4)),
YEAR(Testdate), MONTH(Testdate)
ORDER BY
YEAR(Testdate), MONTH(Testdate)

You need to cast DATETIME into DATE first.
SELECT CAST(TestDate AS DATE) DATE_ONLY,
COUNT(*) totalPost
FROM tableName
GROUP BY CAST(TestDate AS DATE)

Related

Sql remove Null Values in sub queries

I am trying to do sub select queries but i am having Null values in my group by
SELECT convert(varchar, dbo.ArretProductionJournee.DateArret, 3) ,
(select
sum (datediff(minute, ArretProductionJournee.HeureDebut, ArretProductionJournee.HeureFin) )
where ArretProductionJournee.EnumArret Like 'HH')
as HH,
(select
sum (datediff(minute, ArretProductionJournee.HeureDebut, ArretProductionJournee.HeureFin) )
where ArretProductionJournee.EnumArret Like 'HI')
as HI,
(select
sum (datediff(minute, ArretProductionJournee.HeureDebut, ArretProductionJournee.HeureFin) )
where ArretProductionJournee.EnumArret Like 'PS')
as PS
FROM
dbo.ArretProductionJournee
where dbo.ArretProductionJournee.DateArret BETWEEN '01/04/2021'and '03/04/2021'
group by ArretProductionJournee.EnumArret, convert(varchar, dbo.ArretProductionJournee.DateArret, 3)
This results like below :
I want to remove those Null Values to have a result like so :
---------------------------
Date ArrĂȘt | HH | HI | PS |
---------------------------
03 / 02/ 21| 0 | 29 | 45 |
I guess you do not need those sub-SELECTs. Use conditional aggregation instead. Try this.
SELECT CONVERT(varchar, DateArret, 3),
SUM(IIF(EnumArret Like 'HH', datediff(minute, HeureDebut, HeureFin, 0)) AS HH,
SUM(IIF(EnumArret Like 'HI', datediff(minute, HeureDebut, HeureFin, 0)) AS HI,
SUM(IIF(EnumArret Like 'PS', datediff(minute, HeureDebut, HeureFin, 0)) AS PS,
FROM dbo.ArretProductionJournee
WHERE DateArret BETWEEN '01/04/2021'and '03/04/2021'
GROUP BY CONVERT(varchar, DateArret, 3)
It's called conditional aggregation because each SUM(IIF(condition, val, 0)) item only adds up rows matching the condition.
I removed the table names from your column names (ArretProductionJournee.HeureDebut becomes HeureDebut) because you only use one table, and because the query is easier to read that way.
I'm pretty sure you just want conditional aggregation:
select convert(date, dbo.ArretProductionJournee.DateArret),
sum(case when apj.EnumArret = 'HH'
then datediff(minute, apj.HeureDebut, apj.HeureFin)
end) as HH,
sum(case when apj.EnumArret = 'HI'
then datediff(minute, apj.HeureDebut, apj.HeureFin)
end) as HI,
sum(case when apj.EnumArret = 'PS'
then datediff(minute, apj.HeureDebut, apj.HeureFin)
end) as PS
from dbo.ArretProductionJournee apj
where apj.DateArret between '2021-04-01' and '2021-04-03'
group by convert(date, apj.DateArret);

T-SQL. GroupBy Truncated DATETIME and order by

I have a simple table of Orders like:
Order
=========
Date (DATETIME)
Price (INT)
And I would like to know how much money we earned per every month and output should look like:
January-2018 : 100
February-2018: 200
...
January-2019: 300
...
I have the following SQL:
SELECT
DATENAME(MONTH , DATEADD(M, t.MDate , -1 ) ) + '-' + CAST(t.YDate as NVARCHAR(20)),
SUM(Price)
FROM
(
SELECT
DATEPART(YYYY, o.Date) as YDate,
DATEPART(MM, o.Date) as MDate,
Price
FROM [Order] o
) t
GROUP BY t.YDate, t.MDate
ORDER BY t.YDate, t.MDate
Is it ok or may be there is a better approach ?
format() is the way to go. I would recommend:
select format(o.date, 'MMMM-yyyy') as Monthyear,
sum(o.price) as total
from orders o
group by format(datenew, 'MMMM-yyyy')
order by min(o.date)
If you are using Sql server 2012 or + , you can make use of format function as well.
select cast('2018-02-23 15:34:09.390' as datetime) as datenew, 100 as price into #temp union all
select cast('2018-02-24 15:34:09.390' as datetime) as datenew, 300 as price union all
select cast('2018-03-10 15:34:09.390' as datetime) as datenew, 500 as price union all
select cast('2018-03-11 15:34:09.390' as datetime) as datenew, 700 as price union all
select cast('2019-02-23 15:34:09.390' as datetime) as datenew, 900 as price union all
select cast('2019-02-23 15:34:09.390' as datetime) as datenew, 1500 as price
select Monthyear, total from (
select format(datenew, 'MMMM-yyyy') Monthyear, format(datenew, 'yyyyMM') NumMMYY ,sum(price) total from #temp
group by format(datenew, 'MMMM-yyyy') , format(datenew, 'yyyyMM') ) test
order by NumMMYY
Since format will convert it to nvarchar, I had to create one more column in the subquery to order it properly. If you don't mind one more column you don't have to use subquery, and you can order it with another column. I could not find any other way (except for case statement which is not a very good idea) to do it in the same select
Output:
Monthyear Total
February-2018 400
March-2018 1200
February-2019 2400
Maybe just with this?
with Orders as (
select convert(date,'2018-01-15') as [date], 10 as Price union all
select convert(date,'2018-01-20'), 20 union all
select convert(date,'2018-01-30'), 30 union all
select convert(date,'2018-02-15'), 20 union all
select convert(date,'2018-03-15'), 40 union all
select convert(date,'2018-03-20'), 50
)
select
datename(month,o.Date) + '-' + datename(year,o.Date) + ': ' +
convert(varchar(max),SUM(Price))
FROM [Orders] o
group by datename(month,o.Date) + '-' + datename(year,o.Date)
order by 1 desc
I don't get well why are you removing one month in your query, I am not doing it. You can test it here: https://rextester.com/GRKK80105

Left join grouped data(with min/max) without losing rows

Hello and thank you in advance! I have the following query that retrieves the table i need (highlighted in green). The top select statement gets the min(eventdate) and the bottom select statement (that is Unioned) gets a concatenation of min(eventdate) and max(eventdate). This is most important to maintain. This returns the data just fine, but now i'm stuck having to join the rest of the data to this table (highlighted in red).
How can I join without having to group all my columns and lose some data. If you look at the image you can see the data returned because event time doesn't need to be grouped, it's all the same. However, this is not always the case, event time changes even for the same ID. Any help on this would be greatly appreciated.
(Select id,__DisplayName, LEFT(cast(min(EventDate) as varchar), len(min(eventdate)) -7)Eventdate from SP_HS_Marketing_ExtEvents WHERE __ApprovalStatus = 'Approved' and __EventType not in ('1','-1','-2')
group by ID, __DisplayName
Union ALL
Select id,__DisplayName,
LEFT(cast(min(EventDate) as varchar), len(min(eventdate)) -7) + ' - ' + LEFT(cast(max(EventDate) as varchar), len(max(eventdate)) -7) Eventdate from SP_HS_Marketing_ExtEvents WHERE __ApprovalStatus = 'Approved' and __EventType = -2
group by ID, __DisplayName)
Thank you,
Adam
to achieve this you can use a CTE to find the min and max dates, then join back to the original table and concat + cast the date.
With cte as (
Select min(eventdate) as minDate, max(eventdate) as maxDate, Id
from SP_HS_Marketing_ExtEvents
WHERE __ApprovalStatus = 'Approved' and __EventType not in ('1','-1','-2')
group by id
)
Select Distinct s.EventTitle,
DATENAME(MONTH,cte.minDate) + ' ' + DATENAME(DAY,cte.minDate) + ' ' + RIGHT('00' + CAST(YEAR(cte.minDate) AS VARCHAR),2)
+ ' - ' +
DATENAME(MONTH,cte.maxDate) + ' ' + DATENAME(DAY,cte.maxDate) + ' ' + RIGHT('00' + CAST(YEAR(cte.maxDate) AS VARCHAR),2) AS EventDate
,EventTime
,Location
from SP_HS_Marketing_ExtEvents as s
join cte as cte
on cte.ID = s.id
Rextester

Order by year in post date

My sql query is:
SELECT DISTINCT
SUBSTRING(DATENAME(MONTH, PostDate), 1, 3) + '-' + CAST(YEAR(PostDate) AS VARCHAR(4)) AS PostArchive,
Posts = COUNT(*)
FROM
Post WHERE Verified=1
GROUP BY
SUBSTRING(DATENAME(MONTH, PostDate), 1, 3) + '-' + CAST(YEAR(PostDate) AS VARCHAR(4)),
YEAR(PostDate), MONTH(PostDate)
ORDER BY PostArchive
Its gives a result like this:
PostArchive Posts
------------------------
Mar-2009 1
Mar-2010 1
May-2005 1
May-2011 1
May-2012 1
May-2013 1
But I want a result order by date(year) like this.
PostArchive Posts
------------------------
May-2005 1
Mar-2009 1
Mar-2010 1
May-2011 1
May-2012 1
May-2013 1
I search and found this link but unable to solve my problem.
I try :
ORDER BY CONVERT(DateTime, PostArchive,101) DESC
But it gives me a error:
Invalid column name 'PostArchive'.
Is there any way to do this or I am in wrong way.Thanks.
The reason for the error is that PostArchive is the name you've given to the column on the SELECT line, which is effectively the output of the query. The ORDER BY clause does not look at that, it looks at its input to the query, which in this case is PostDate
I assume that you didn't really mean that you want to order it by
year, but instead by year/month. The ordering issue that you have is
because you are ordering it as a character and not as a date.
You don't need DISTINCT, since you already GROUP BY.
Main problem is that you already converted to VARCHAR. Hence, months
are unsortable.
ssss
-- Create a CTE (inline view)
WITH T AS (
SELECT YEAR(PostDate) PostYear
, MONTH(PostDate) PostMM
, SUBSTRING(DATENAME(MONTH, PostDate),1,3) PostMonth
, COUNT(*) Posts
FROM Post
WHERE Verified = 1
GROUP BY YEAR(PostDate)
, MONTH(PostDate)
, DATENAME(MONTH, PostDate)
)
-- Build you date string
SELECT PostMonth + '-' + CAST(PostYear AS VARCHAR(4)) AS PostArchive
, Posts
FROM T
-- Sort it by the components separately
ORDER BY PostYear
-- Don't use the character, otherwise, Aug will come before Mar
, PostMM
I used CTE to get the result try this
with tempTable (PostArchiveMonth , PostArchiveYear , PostArchiveMonthName , Posts )
(
select month(PostDate) , YEAR(PostDate) , SUBSTRING(DATENAME(MONTH, PostDate), 1, 3)
COUNT(*)
FROM Post
WHERE Verified=1
group by MONTH(PostDate) ,YEAR( PostDate)
,SUBSTRING(DATENAME(MONTH, PostDate), 1, 3)
)
select PostArchiveMonthName +'-' + PostArchiveYear as PostArchive , Posts
from tempTable
order by PostArchiveYear , PostArchiveMonth
Try
SELECT DISTINCT
SUBSTRING(DATENAME(MONTH, PostDate), 1, 3) + '-' + CAST(YEAR(PostDate) AS VARCHAR(4)) AS PostArchive,
Posts = COUNT(*)
FROM
Post WHERE Verified=1
GROUP BY
SUBSTRING(DATENAME(MONTH, PostDate), 1, 3) + '-' + CAST(YEAR(PostDate) AS VARCHAR(4)),
YEAR(PostDate), MONTH(PostDate)
Order by Month(PostDate), Year(PostDate)
Try to change this:
ORDER BY PostArchive
...to this...
ORDER BY YEAR(PostDate)

Using SELECT result in another SELECT

So here is my query
SELECT
*
FROM
Score AS NewScores
WHERE
InsertedDate >= DATEADD(mm, -3, GETDATE());
SELECT
ROW_NUMBER() OVER( ORDER BY NETT) AS Rank,
Name,
FlagImg,
Nett,
Rounds
FROM (
SELECT
Members.FirstName + ' ' + Members.LastName AS Name,
CASE
WHEN MenuCountry.ImgURL IS NULL THEN
'~/images/flags/ismygolf.png'
ELSE
MenuCountry.ImgURL
END AS FlagImg,
AVG(CAST(NewScores.NetScore AS DECIMAL(18, 4))) AS Nett,
COUNT(Score.ScoreID) AS Rounds
FROM
Members
INNER JOIN
Score
ON Members.MemberID = Score.MemberID
LEFT OUTER JOIN MenuCountry
ON Members.Country = MenuCountry.ID
WHERE
Members.Status = 1
GROUP BY
Members.FirstName + ' ' + Members.LastName,
MenuCountry.ImgURL
) AS Dertbl
ORDER BY;
The query is to give a result set for a GridView based leaderboard and what I want is to only get the average of Scores that are less than 3 months old. I have this in 2 parts as you can see and obviously it gives an error like this.
Msg 4104, Level 16, State 1, Line 2
The multi-part identifier "NewScores.NetScore" could not be bound.
Which is because of this AVG(CAST(NewScores.NetScore AS DECIMAL(18, 4))) AS Nett
How do I make it so that I can use NewScores there so I'm only getting the average of the scores less than 3 months old?
EDIT: Using the answers people provided I've solved it by using a join in the correct place and here is the correct query:
SELECT ROW_NUMBER() OVER(ORDER BY NETT) AS Rank, Name, FlagImg, Nett, Rounds FROM (SELECT Members.FirstName + ' ' + Members.LastName AS Name, CASE WHEN MenuCountry.ImgURL IS NULL THEN '~/images/flags/ismygolf.png' ELSE MenuCountry.ImgURL END AS FlagImg, AVG(CAST(NewScores.NetScore AS DECIMAL(18, 4))) AS Nett, COUNT(NewScores.ScoreID) AS Rounds FROM Members INNER JOIN (SELECT * FROM Score WHERE InsertedDate >= DATEADD(mm, -5, GETDATE())) NewScores ON Members.MemberID = NewScores.MemberID LEFT OUTER JOIN MenuCountry ON Members.Country = MenuCountry.ID WHERE Members.Status = 1 GROUP BY Members.FirstName + ' ' + Members.LastName, MenuCountry.ImgURL) AS Dertbl ORDER BY Nett ASC
NewScores is an alias to Scores table - it looks like you can combine the queries as follows:
SELECT
ROW_NUMBER() OVER( ORDER BY NETT) AS Rank,
Name,
FlagImg,
Nett,
Rounds
FROM (
SELECT
Members.FirstName + ' ' + Members.LastName AS Name,
CASE
WHEN MenuCountry.ImgURL IS NULL THEN
'~/images/flags/ismygolf.png'
ELSE
MenuCountry.ImgURL
END AS FlagImg,
AVG(CAST(NewScores.NetScore AS DECIMAL(18, 4))) AS Nett,
COUNT(Score.ScoreID) AS Rounds
FROM
Members
INNER JOIN
Score NewScores
ON Members.MemberID = NewScores.MemberID
LEFT OUTER JOIN MenuCountry
ON Members.Country = MenuCountry.ID
WHERE
Members.Status = 1
AND NewScores.InsertedDate >= DATEADD(mm, -3, GETDATE())
GROUP BY
Members.FirstName + ' ' + Members.LastName,
MenuCountry.ImgURL
) AS Dertbl
ORDER BY;
What you are looking for is a query with WITH clause, if your dbms supports it. Then
WITH NewScores AS (
SELECT *
FROM Score
WHERE InsertedDate >= DATEADD(mm, -3, GETDATE())
)
SELECT
<and the rest of your query>
;
Note that there is no ; in the first half. HTH.
You are missing table NewScores, so it can't be found. Just join this table.
If you really want to avoid joining it directly you can replace NewScores.NetScore with SELECT NetScore FROM NewScores WHERE {conditions on which they should be matched}