Order by year in post date - sql

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)

Related

Add a leading zero to months less than 10 and trim 4 digit years to 2 digits

I need to print manipulate month and string which I fetch from a table and display in the format like '12/20', '11/20', 09/20'
For this I need to trim the last 2 digits from year and also a leading zero to months which are less than 10.
SELECT
CAST(MONTH(O.AddDate) AS VARCHAR(2)) + '/' + CAST(YEAR(O.AddDate) AS VARCHAR(4)) AS TimeStamp
FROM
[Order] O
WHERE
O.CountryCode = 9009
GROUP BY
CAST(MONTH(O.AddDate) AS VARCHAR(2)) + '/' + CAST(YEAR(O.AddDate) AS VARCHAR(4))
This provided output in the format of '10/2020', '8/2020' but I require it to be like '08/20', '10/20'
You can use format():
select format(O.AddDate, 'MM/yy') as timestamp
from [Order] o
group by format(O.AddDate, 'MM/yy')
Obviously that's not your entire query; otherwise, if you have no aggregation function in the select clause, you can use select distinct instead of group by.
IMHO formatting dates is a presentation layer concern. SQL Server should provide the data and presentation layer should show the data to user as required. So I would write the query like this:
SELECT DISTINCT
YEAR(O.AddDate) AS AddDateYear, MONTH(O.AddDate) AS AddDateMonth
FROM
[Order] O
WHERE
O.CountryCode = 9009
Or like this:
SELECT
YEAR(O.AddDate) AS AddDateYear, MONTH(O.AddDate) AS AddDateMonth
FROM
[Order] O
WHERE
O.CountryCode = 9009
GROUP BY
YEAR(O.AddDate), MONTH(O.AddDate)
However, if you insist in formatting the date like you requested, then here is the query:
SELECT
RIGHT('0' + CAST(T.AddDateMonth AS varchar(2)), 2) + '/'
+ RIGHT(CAST(T.AddDateYear) AS varchar(4), 2) AS Y2kVulnerableTimestamp
FROM
(
SELECT DISTINCT
YEAR(O.AddDate) AS AddDateYear, MONTH(O.AddDate) AS AddDateMonth
FROM
[Order] O
WHERE
O.CountryCode = 9009
) T

Duplicate rows when trying to grab last row of another table

I am trying to grab the last (latest) blog article's link for each month using a stored procedure but I cannot seem to find a way past my problem.
Currently, my code below repeats the (the latest blog article's) 'LINK' column like so:
SELECT AVG(DATEPART(mm, b.blog_date)) AS MonthNum --CANNOT USE MONTHNUM IN ORDER BY UNLESS WRAPPED WITH AVG() [average], weird but works
, CAST(DateName(month, DateAdd(month, Datepart(MONTH, b.blog_date), -1)) AS varchar(24)) AS MONTH
, CAST(DATEPART(YEAR, b.blog_date) AS varchar(4)) AS YEAR
, CAST(count(b.blog_content) AS varchar(24)) as ARTICLES
, (SELECT TOP (1) b.blog_url
FROM Management.Blog
WHERE (website_owner_id = 2)
GROUP BY blog_date
, blog_url
ORDER BY blog_date DESC
) AS LINK
, CAST(DateName(month, DateAdd(month, Datepart(MONTH, b.blog_date), -1)) AS varchar(24)) + CAST(DATEPART(YEAR, b.blog_date) AS varchar(4)) AS ID
, blog_date as DATE
FROM Management.Blog b
WHERE b.website_owner_id = 2
GROUP BY CAST(DateName(month, DateAdd(month, Datepart(MONTH, b.blog_date), -1)) AS varchar(24))
, CAST(DATEPART(YEAR, b.blog_date) AS varchar(4))
, b.blog_url
, blog_date
, CAST(DateName(month, DateAdd(month, Datepart(MONTH, b.blog_date), -1)) AS varchar(24)) + CAST(DATEPART(YEAR, b.blog_date) AS varchar(4))
ORDER BY DATE DESC
I understand the code is horrible to read (& probably to execute on the SQL server too) but I'm in a position where I am only new to SQL server (coming from MySQL where I've only really had to use a basic select query) and I am open to any suggestions to changing the query and/or table design.
Essentially there should be no duplicates of the ID column (which is only really added in to assist in removing the duplicates and can be omitted if need be).
Without sample data I'm unable to test whether this would work
After FROM Management.Blog b
Add this
INNER JOIN(
SELECT MonthNum = DATEPART(MONTH, BL.blog_date))
,blog_date
,RN = ROW_NUMBER()OVER(ORDER BY BL.blog_date DESC)
,BL.blog_url
FROM Management.Blog BL
) X ON B.blog_date = X.blog_date
AND X.RN = 1
Replace
(SELECT TOP (1) b.blog_url
FROM Management.Blog
WHERE (website_owner_id = 2)
GROUP BY blog_date
, blog_url
ORDER BY blog_date DESC
) AS LINK
with
X.blog_url AS [LINK]
change this in GROUP BY
, b.blog_url
with
, x.blog_url
I non-functioning query usually does not do a very good job of conveying what someone wants. Based on your explanation:
I am trying to grab the last (latest) blog article's link for each month
I would expect something like this:
SELECT b.*
FROM (SELECT b.*,
ROW_NUMBER() OVER (PARTITION BY YEAR(b.blog_date), MONTH(b.blog_date), b.blog_url, b.website_owner_id
ORDER BY blog_date DESC
) as seqnum
FROM Management.Blog b
) b
WHERE b.website_owner_id = 2 AND
seqnum = 1;

Group only specific values and get min and max dates

Hello and thank you in advance, not sure my title will suffice but hoping the image with the desired output will help. Essentially, the data where eventtype=2 needs to be grouped by ID. Once grouped, I still need to concatenate the Min(eventdate) and max(eventdate).
The First image is just the simple select statment(select * from TABLE).
Any help would be greatly appreciated.
SELECT __DisplayName,
EventDate,
RIGHT(CONVERT(varchar(20),DATEADD(HOUR, -5 , EventDate), 100),7)
+ ' to ' +
RIGHT(CONVERT(varchar(20), DATEADD(HOUR, -5 , EndDate), 100),7),
location,
__EventType
FROM (SELECT *,
ROW_NUMBER() OVER
( PARTITION BY Id
ORDER BY eventdate asc
) AS ROWNUM
FROM TABLE
) x
WHERE ROWNUM = 1
AND __ApprovalStatus = 'Approved'
AND __EventType not in ('1','-1');
Thank you all for your input. YOu led me to the right answer. SO what I did is essentially union two queries. One that gets all data where eventtype is not in -1,1, and -2 and then another query that essentially concatenates the min and max but only where event type = -2
(Select __DisplayName, cast(min(EventDate)as varchar) Eventdate from TABLE WHERE __ApprovalStatus = 'Approved' and __EventType not in ('1','-1','-2')
group by ID, __DisplayName
Union ALL
Select __DisplayName,
cast(min(EventDate)as varchar) + ' - ' + cast(max(EventDate) as varchar) Eventdate from TABLE WHERE __ApprovalStatus = 'Approved' and __EventType = -2 group by ID, __DisplayName)
order by Eventdate

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}

Select Distinct date and Count

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)