0 come last when sorting ascending - sql

I am trying to select from one table a list of products ordered by price, year, name, and others....
The problem is that I must make zero values come last when sorting ascending.
My code is:
SELECT * FROM Product P
ORDER BY CASE WHEN #OrderBy='Date ASC' THEN Date END ASC,
CASE WHEN #OrderBy='Price ASC' THEN Price END ASC,
CASE WHEN #OrderBy='Title ASC' THEN Title END ASC,
CASE WHEN #OrderBy='' THEN Match END
This works but don't put the zero at the bottom of the list.
So, I tried to transform it (see next code), but it gave me the error Incorrect syntax near ','.
SELECT * FROM Product P
ORDER BY CASE WHEN #OrderBy='Price ASC' THEN
(case A.Price WHEN 0 THEN 1 ELSE 0 END,A.Price )
END ASC
I appreciate any help

You can do it by testing for price-ordering twice:
SELECT * FROM Product P
ORDER BY CASE WHEN #OrderBy='Date ASC' THEN Date END ASC,
CASE WHEN #OrderBy='Price ASC' THEN CASE WHEN Price = 0 THEN 1 ELSE 0 END ASC,
CASE WHEN #OrderBy='Price ASC' THEN Price END ASC,
CASE WHEN #OrderBy='Title ASC' THEN Title END ASC,
CASE WHEN #OrderBy='' THEN Match END
By the way, the implicit value of the case expression when #orderBy doesn't equal the string is null. When the sort column contains all nulls, it effectively disables sorting for that attribute.

I would suggest using a large dummy price:
ORDER BY CASE WHEN #OrderBy='Price ASC' THEN 99999999 ELSE A.Price END ASC
or if you DBMS supports NULLS LAST:
ORDER BY CASE WHEN #OrderBy='Price ASC' THEN NULLIF(A.Price,0) END ASC NULLS LAST

You can try with this syntax:
SELECT *,
CASE WHEN #OrderBy = 'Price ASC' AND Price = 0 THEN 1 ELSE 0 END AS OrderPriceZeroLast
FROM Product P
ORDER BY OrderPriceZeroLast,
CASE WHEN #OrderBy = 'Date ASC' THEN Date END ASC,
CASE WHEN #OrderBy = 'Price ASC' THEN Price END ASC,
CASE WHEN #OrderBy = 'Title ASC' THEN Title END ASC,
CASE WHEN #OrderBy = '' THEN Match END

I can't add comments yet. There is bug in your code
SELECT * FROM Product P
ORDER BY CASE WHEN #OrderBy='Price ASC' THEN
(case A.Price WHEN 0 THEN 1 ELSE 0 END,A.Price )
END ASC
Shoud be smth like
SELECT *
FROM Product P
ORDER BY
CASE
WHEN #OrderBy='Price ASC'
THEN
CASE A.Price
WHEN 0
THEN 1
ELSE 0
END
END,
A.Price

This may seem like a hack but you could create a new column on the result set on the fly. Like this:
SELECT *, [name of column that may contain zeroes] as foo WHERE /* rest of your code */
Then you could sort DESC on foo and ASC on the rest. Just remember to now show foo to the user. Also notice that yes, you'll get the same column in the result set twice. You also have to use a CASE to turn all non-zero values into 1 (or some other constant value).

Try this to sort 0 value to last, when there are 0,1,2,... values are in field.
It will bring 1, 2 ,... and 0 to last order.
select * from Product
order by
case
when OrderBy = 0
then -1
else 0
end,
OrderBy desc
-Chirag

Related

CASE expression when with multiple column order

Posted value if 0 then, make the order according to these columns: isl_tar, isl_saat, ref_kod, isl_ref, kayit_no
Posted value if 1 then make the order according to this column: tutar
This script is not working:
I want to sort by the second case
select t.*
from TEMP_HESAP_HAREKET t
order by case 1
when 0 then
TO_NUMBER(TO_CHAR(ISL_TAR, 'YYYYMMDD') ||
SUBSTR(ISL_SAAT, 1, 2) || SUBSTR(ISL_SAAT, 4, 2))
end asc,
REF_KOD asc,
ISL_REF asc,
KAYIT_NO asc,
case 1
when 1 then
tutar end
You seem to want:
order by (case 1 when 1 then tutar end), -- handle that case first
TO_NUMBER(TO_CHAR(ISL_TAR, 'YYYYMMDD') ||
SUBSTR(ISL_SAAT, 1, 2) || SUBSTR(ISL_SAAT, 4, 2))
REF_KOD asc,
ISL_REF asc,
KAYIT_NO asc
I assume the expression on isl_tar is correct. It seems like a simple column reference would suffice.
I assume the value after the CASE gets put there somehow, maybe by some application which fires the statement.
Then you could order by five CASE.
If the value is 0 then return the respective column from your list of columns you want to sort in case of a 0.
In the first CASE return tutar if the value is 1. In all the other CASE, if the value is 1, return always the same value or none at all (NULL) which will be the default anyway, if you don't have a WHEN for it in there at all.
ORDER BY CASE ?
WHEN 0 THEN
ISL_TAR
WHEN 1 THEN
TUTAR
END ASC,
CASE ?
WHEN 0 THEN
ISL_SAAT
END ASC,
CASE ?
WHEN 0 THEN
REF_KOD
END ASC,
CASE ?
WHEN 0 THEN
ISL_REF
END ASC,
CASE ?
WHEN 0 THEN
KAYIT_NO
END ASC
The ? have to be replaced with the 0 or 1.
However, if there is an application placing the values after the CASE, it might be a "cleaner" (easier to read, understand and maintain) way to make it change the complete ORDER BY expression instead of putting the 0 or 1.

How to sort data in stored procedure with column positions of select statement with CASE

This is not working
ORDER BY
CASE
WHEN #OrderBy = 'EndDateInDays' AND #OrderByDirection = 'D'
THEN 10
END DESC,
CASE
WHEN #OrderBy = 'EndDateInDays' AND #OrderByDirection != 'D'
THEN 10
END
Where this one is working
ORDER BY 10 DESC
As per documentation,
ORDER BY order_by_expression
order_by_expression Specifies a column or expression on which to sort
the query result set. A sort column can be specified as a name or
column alias, or a nonnegative integer representing the position of
the column in the select list.
Source: SELECT - ORDER BY Clause (Transact-SQL)
You are specifying an expression, hence the SQL Server does not sort by value in column #10. Instead it sorts your rows by a constant value '10', which results in no sort being performed.
Suggested solution
Move all complex columns into a CROSS APPLY sub-query and add another CROSS APPLY with a sorting column:
SELECT F.Id
,cols.Favourite
,F.Agent
,F.Name
,cols.DatePublished
,UF.ToolTip
,F.CreationDate
FROM MyTable F
INNER JOIN MyTable2 UF
ON f.Id = UF.Id
CROSS APPLY (
SELECT (CASE WHEN UFF.[Id] IS NULL THEN CONVERT(BIT, 0) ELSE CONVERT(BIT, 1) END) AS Favourite
,CONVERT(Datetime, F.[Date] , 103) AS DatePublished
) cols
CROSS APPLY (
SELECT -- Make sure to correctly cast all numeric and date values to text
CASE WHEN #OrderBy = 'EndDateInDays' THEN CONVERT(VARCHAR(100), F.[EndDateDate], 126)
WHEN #OrderBy = 'Name' THEN F.Name
WHEN #OrderBy = 'DatePublished' THEN cols.DatePublished
ELSE CONVERT(VARCHAR(100), F.Id) -- This is default sort
END AS [SortCol]
) sort
ORDER BY
CASE WHEN #OrderByDirection = 'D' THEN sort.[SortCol] END DESC
,CASE WHEN #OrderByDirection != 'D' THEN sort.[SortCol] END
;
You can use the column alias. Let's say it is EndDateInDays:
ORDER BY (CASE WHEN #OrderBy = 'EndDateInDays' AND #OrderByDirection = 'D'
THEN EndDateInDays
END) DESC,
(CASE WHEN #OrderBy = 'EndDateInDays' AND #OrderByDirection <> 'D'
THEN EndDateInDays
END)
If EndDateInDays is a number (as suggested by the name), you could do:
ORDER BY (CASE WHEN #OrderBy = 'EndDateInDays' AND #OrderByDirection = 'D'
THEN - EndDateInDays
WHEN #OrderBy = 'EndDateInDays' AND #OrderByDirection <> 'D'
THEN EndDateInDays
END)
Also, be careful if you start combining multiple columns. It is better to have a separate CASE expression for each column to prevent inadvertent type mismatching.

CASE Statement for Order By Clause with Multiple Columns and Desc/Asc Sort

Following on from my earlier question here Case statement for Order By clause with Desc/Asc sort I have a statement like this:
SELECT
*
FROM
TableName
WHERE
ORDER BY
CASE #OrderByColumn WHEN 1 THEN Forename END DESC,
CASE #OrderByColumn WHEN 2 THEN Surname END ASC
This works well, but sometimes I need more than column in the order by. I actually need something like this:
.....
ORDER BY
CASE #OrderByColumn WHEN 1 THEN Forename, Date, Location END DESC
I can't work out how to make the CASE statement allow multiple columns in the THEN part.
You can write multiple cases, even if they all have the same condition.
ORDER BY
CASE #OrderByColumn WHEN 1 THEN Forename END DESC,
CASE #OrderByColumn WHEN 1 THEN Date END,
CASE #OrderByColumn WHEN 1 THEN Location END,
CASE #OrderByColumn WHEN 2 THEN Surname END ASC
Actually, you don't specify a column to sort by, but an expression.
The case statement returns null if the condition is not met, so actually it means:
CASE #OrderByColumn WHEN 1 THEN Forename ELSE NULL END
So if #OrderByColumn is not 1 then the statement returns always NULL. That doesn't exclude it from sorting, by the way, but it puts all those rows together in the result, making 'SurName' the decisive sorting within that group of rows.
Do you need this?
ORDER BY
CASE #OrderByColumn WHEN 1 THEN Forename END DESC, Date, Location,
CASE #OrderByColumn WHEN 2 THEN Surname END ASC
This is better if you want to give sort keyword as well
ORDER BY
CASE WHEN #SortExpression = 'Id ASC' THEN Id END ASC,
CASE WHEN #SortExpression = 'Id DESC' THEN Id END DESC,

SQL: Order first by table.column = 'matchingstring', then order everything else alphabetically?

I'm currently using MySQL and I want to order my book_versions records where the book_versions.name = 'paperback' show up first, and then the rest of the book_versions (book_versions.name != 'paperback') show. How would I accomplish this?
order by case when book_versions.name = 'paperback' then 0 else 1 end,
book_versions.name, -- remove this line if other names should not be ordered
book_versions.isbn
See sqlFiddle to see the difference
in mysql, you can also use field
order by field(book_versions.name, 'paperback') DESC,
book_versions.name ASC,
book_versions.isbn ASC
Try:
ORDER BY
CASE WHEN book_versions.name = 'paperback' THEN 0 ELSE 1 END, -- puts paperbacks first (because paperbacks cause this to =0, which is ordered before 1)
book_versions.name -- then order alphabetically

T SQL Chain join 4 tables

Here is the scenario:
I have tables:
Articles (articleId, userId, title, datePosted)
ArticleTranslations (languageId, articleId, title) (not so important for this case, but I am showing anyway)
ArticleSections (articleSectionId, articleId, sectionId)
sections (sectionId, content, ...)
sectionsAdditionalInfo (sectionId, isApproved)
What I am doing is selecting some articles from articles by userId in a way:
SELECT article.articleId, article.userId, ArticleTranslations.title, article.datePosted
FROM Articles
LEFT OUTER JOIN ArticleTranslations ON Article.articleId= ArticlesTranslations.articleId AND ArticlesTranslations.languageId=#languageId
WHERE Articloes.userId=#userId
ORDER BY
CASE WHEN #sortDirection = 'DD' THEN datePosted END DESC, -- by date posted
CASE WHEN #sortDirection = 'DA' THEN datePosted END,
CASE WHEN #sortDirection = 'ND' THEN title END DESC, -- sort by name
CASE WHEN #sortDirection = 'NA' THEN title END,
CASE WHEN #sortDirection = 'SD' THEN ArticleTranslations.isApproved END DESC, -- is article aproved?
CASE WHEN #sortDirection = 'SA' THEN ArticleTranslations.isApproved END,
CASE WHEN #sortDirection = 'ID' THEN areAllSectionsApproved END DESC, -- sort by information if sections are all approved - within the article?
CASE WHEN #sortDirection = 'IA' THEN areAllSectionsApproved END
Please bare in mind I left out some of the info in order for my question to be more understandable.
Now, what I would like to do is select another attribute (for each article returned in SQL above): areAllArticleSectionsApproved
I have assembled SQL separately, but I would like this to be returned for every row:
SELECT CASE WHEN COUNT(sectionsAdditionalInfo.sectionId) > 0 THEN 0 ELSE 1 END AS areAllSectionsApproved
FROM ArticleSections
LEFT OUTER JOIN sectionsAdditionalInfo ON ArticleSections.sectionId = sectionsAdditionalInfo.sectionId
WHERE articleId=#articleId AND sectionsAdditionalInfo.isApproved=0
I have tried nesting this SQL, in a way:
SELECT (outer SQL) .....
a.*(
nested SQL - second one I posted here
) as a
but it didn't work at all.
I am using SQL server 2008.
Any hint on how to solve this would be greatly appreciated ;)
Without fully understanding your data and your desired results, something like this should work using your above query and joining on your second query as a subquery:
SELECT article.articleId,
article.userId,
ArticleTranslations.title,
article.datePosted,
t.areAllSectionsApproved
FROM Articles
LEFT OUTER JOIN ArticleTranslations
ON Article.articleId= ArticlesTranslations.articleId
AND ArticlesTranslations.languageId=#languageId
LEFT JOIN (
SELECT
articleId,
CASE
WHEN COUNT(sectionsAdditionalInfo.sectionId) > 0
THEN 0
ELSE 1
END AS areAllSectionsApproved
FROM ArticleSections
LEFT OUTER JOIN sectionsAdditionalInfo
ON ArticleSections.sectionId = sectionsAdditionalInfo.sectionId
WHERE sectionsAdditionalInfo.isApproved=0
GROUP BY articleId
) t ON articles.articleId = t.articleId
WHERE Articloes.userId=#userId
ORDER BY
CASE WHEN #sortDirection = 'DD' THEN datePosted END DESC, -- by date posted
CASE WHEN #sortDirection = 'DA' THEN datePosted END,
CASE WHEN #sortDirection = 'ND' THEN title END DESC, -- sort by name
CASE WHEN #sortDirection = 'NA' THEN title END,
CASE WHEN #sortDirection = 'SD' THEN ArticleTranslations.isApproved END DESC, -- is article aproved?
CASE WHEN #sortDirection = 'SA' THEN ArticleTranslations.isApproved END,
CASE WHEN #sortDirection = 'ID' THEN areAllSectionsApproved END DESC, -- sort by information if sections are all approved - within the article?
CASE WHEN #sortDirection = 'IA' THEN areAllSectionsApproved END
Good luck.