SQL Order By Except When You Don't - sql

I want to retrieve a full table with some of the values sorted. The sorted values should all appear before the unsorted values. I though I could pull this off with a UNION but order by is only valid to use after unioning the table and my set of data isn't set up such that that is useful in this case. I want rows with a column value of 0-6 to show up sorted in DESC order and then the rest of the results to show up after that. Is there some way to specify a condition in the order by clause? I saw something that looked close to what I wanted to so but I couldn't get the equality condition working in sql. I'm going to try to make a query using WHEN cases but I'm not sure if there's a way to specify a case like currentValue <= 6. If anyone has any suggestions that would be awesome.

You could do something like this:
order by (case when currentValue <= 6 then 1 else 0 end) desc,
(case when currentValue <= 6 then column end) desc
The first puts the values you care about first. The second puts them in sorted order. The rest will be ordered arbitrarily.

Try this:
SELECT *
FROM yourdata
ORDER BY CASE WHEN yourColumn BETWEEN 0 AND 6 THEN yourColumn ELSE -1 End Desc

One RDBMS-agnostic solution would be to add a second field that takes the same value as the field you wish to sort when that field is less than or equal to six. Then just sort by that field.

Related

Return a 0 if no rows are found in Microsoft SQL Server

I need your help with this query.
My table CSO_EMP_ORG_DPM_VIE has a column with different keys. Column name is EXT_KEY.
When I receive the same key number in EXT_KEY, I want the SQL code to count the duplicates using this query:
select EXT_KEY
from CSO_EMP_ORG_DPM_VIE
group by EXT_KEY
having count(*) > 1
This is working so far, but when it has no duplicate keys (numbers) in the column, I want it to generate it with 0 zero, and not nothing.
My expected result is; when two keys are the same I want to generate a 1. When no keys are the same, I want to generate an 0. Right now i got no result at all like in the screenshot.
How can I fix this SQL query accordingly?
Thank you in advance.
Use a CASE expression like this:
SELECT EXT_KEY,
CASE WHEN COUNT(*) > 1 THEN 1 ELSE 0 END flag
FROM CSO_EMP_ORG_DPM_VIE
GROUP by EXT_KEY
or if you want 1 result for the table:
SELECT CASE WHEN COUNT(EXT_KEY) > COUNT(DISTINCT EXT_KEY) THEN 1 ELSE 0 END flag
FROM CSO_EMP_ORG_DPM_VIE
It's not blindingly obvious as to what you are asking for. To that end, this query gives a 1/0 result based on having a count greater than 0 for each key...
SELECT
p.EXT_KEY,
EXT_KEY_RESULT = ISNULL((SELECT 1
FROM CSO_EMP_ORG_DPM_VIE c
WHERE c.EXT_KEY = p.EXT_KEY
HAVING COUNT(EXT_KEY) > 0), 0)
FROM
CSO_EMP_ORG_DPM_VIE p
Alternatively, if you are looking to count each of the keys, you could try...
SELECT EXT_KEY, COUNT(EXT_KEY)
FROM CSO_EMP_ORG_DPM_VIE
GROUP BY EXT_KEY
It's always good practice to specify a particular field in the COUNT aggregate, particularly the primary key, as it's faster to reference.
You really need to give us an expected result for your requirements and be very clear about your expectations.
SELECT CASE WHEN COUNT(EXT_KEY) > 0 THEN 1 ELSE 0 AS dupes
FROM CSO_EMP_ORG_DPM_VIE
PLEASE NOTE: Credit here to forpas for providing a smoother answer which I have borrowed.

How to get 0 if no row found from sql query in sql server

I am getting blank value with this query from sql server
SELECT TOP 1 Amount from PaymentDetails WHERE Id = '5678'
it has no row,that is why its returning blank,So I want if no row then it should return 0
I already tried with COALESCE ,but its not working
how to solve this?
You are selecting an arbitrary amount, so one method is aggregation:
SELECT COALESCE(MAX(Amount), 0)
FROM PaymentDetails
WHERE Id = '5678';
Note that if id is a number, then don't use single quotes for the comparison.
To be honest, I would expect SUM() to be more useful than an arbitrary value:
SELECT COALESCE(SUM(Amount), 0)
FROM PaymentDetails
WHERE Id = '5678';
You can wrap the subquery in an ISNULL:
SELECT ISNULL((SELECT TOP 1 Amount from PaymentDetails WHERE Id = '5678' ORDER BY ????),0) AS Amount;
Don't forget to add a column (or columns) to your ORDER BY as otherwise you will get inconsistent results when more than one row has the same value for Id. If Id is unique, however, then remove both the TOP and ORDER BY as they aren't needed.
You should never, however, use TOP without an ORDER BY unless you are "happy" with inconsistent results.

SQL Query - how do I order part of my data in alphabetical order, and part by id

I have a small piece of data (15 records) where part of it I want ordered in alphabetical order, and part of it ordered by ID
Image 1 shows my data in the original order
After doing the query SELECT * FROM tableName ORDER BY code;
Image 2 shows my data now in alphabetical order, which is great however I would like the top 2 records to be ordered by id
Image 3 shows how I would like my data to look
Could someone help with my query please?
i assumed id is an integer. You can use conditional CASE in the ORDER BY clause.
Note for the first expression case when code in ('LUX-INT', 'LUX-CONT') then -id end desc, it will return id or NULL. As NULL will comes first in ORDER BY, I use DESC and negate the id value so that id is in ascending order
order by case when code in ('LUX-INT', 'LUX-CONT') then -id end desc, code
use case when
SELECT * FROM tableName ORDER BY case when code in ('LUX INT','LUX-CONT') then id else code end
I would write this as:
order by (case when code in ('LUX-INT', 'LUX-CONT') then 1 else 2 end), -- put the special codes first
(case when code in ('LUX-INT', 'LUX-CONT') then code end), -- order them alphabetically
id -- order the rest by id
This works regardless of the types and collations of the underlying columns.

What is "Select -1", and how is it different from "Select 1"?

I have the following query that is part of a common table expression. I don't understand the function of the "Select -1" statement. It is obviously different than the "Select 1" that is used in "EXISTS" statements. Any ideas?
select days_old,
count(express_cd),
count(*),
case
when round(count(express_cd)*100.0/count(*),2) < 1 then '0'
else ''
end ||
cast(decimal(round(count(express_cd)*100.0/count(*),2),5,2) as varchar(7)) ||
'%'
from foo.bar
group by days_old
union all
select -1, -- Selecting the -1 here
count(express_cd),
count(*),
case
when round(count(express_cd)*100.0/count(*),2) < 1 then '0'
else ''
end ||
cast(decimal(round(count(express_cd)*100.0/count(*),2),5,2) as varchar(7)) ||
'%'
from foo.bar
where days_old between 1 and 7
It's just selecting the number "minus one" for each row returned, just like "select 1" will select the number "one" for each row returned.
There is nothing special about the "select 1" syntax uses in EXISTS statements by the way; it's just selecting some random value because EXISTS requires a record to be returned and a record needs data; the number 1 is sufficient.
Why you would do this, I have no idea.
When you have a union statement, each part of the union must contain the same columns. From what I read when I look at this, the first statement is giving you one line for each days old value and then some stats for each day old. The second part of the union is giving you a summary of all the records that are only a week or so less. Since days old column is not relevant here, they put in a fake value as a placeholder in order to do the union. OF course this is just a guess based on reading thousands of queries through the years. To be sure, I would need to actually run teh code.
Since you say this is a CTE, to really understand why this is is happening, you may need to look at the data it generates and how that data is used in the next query that uses the CTE. That might answer your question.
What you have asked is basically about a business rule unique to your company. The true answer should lie in any requirements documents for the original creation of the code. You should go look for them and read them. We can make guesses based on our own experience but only people in your company can answer the why question here.
If you can't find the documentation, then you need to talk (Yes directly talk, preferably in person) to the Stakeholders who use the data and find out what their needs were. Only do this after running the code and analyzing the results to better understand the meaning of the data returned.
Based on your query, all the records with days_old between 1 and 7 will be output as '-1', that is what select -1 does, nothing special here and there is no difference between select -1 and select 1 in exists, both will output the records as either 1 or -1, they are doing the same thing to check whether if there has any data.
Back to your query, I noticed that you have a union all and compare each four columns you select connected by union all, I am guessing your task is to get a final result with days_old not between 1 and 7 and combine the result with day_old, which is one because you take all between 1 and 7.
It is just a grouping logic there.
Your query returns aggregated
data (counts and rounds) grouped by days_old column plus one more group for data where days_old between 1 and 7.
So, -1 is just another additional group there, it cannot be 1 because days_old=1 is an another valid group.
result will be like this:
row1: days_old=1 count(*)=2 ...
row2: days_old=3 count(*)=5 ...
row3: days_old=9 count(*)=6 ...
row4: days_old=-1 count(*)=7

How to do this query in T-SQL

I have table with 3 columns A B C.
I want to select * from this table, but ordered by a specific ordering of column A.
In other words, lets' say column A contains "stack", "over", "flow".
I want to select * from this table, and order by column A in this specific ordering: "stack", "flow", "over" - which is neither ascending nor descending.
Is it possible?
You can use a CASE statement in the ORDER BY clause. For example ...
SELECT *
FROM Table
ORDER BY
CASE A
WHEN 'stack' THEN 1
WHEN 'over' THEN 2
WHEN 'flow' THEN 3
ELSE NULL
END
Check out Defining a Custom Sort Order for more details.
A couple of solutions:
Create another table with your sort order, join on Column A to the new table (which would be something like TERM as STRING, SORTORDER as INT). Because things always change, this avoids hard coding anything and is the solution I would recommend for real world use.
If you don't want the flexibility of adding new terms and orders, just use a CASE statement to transform each term into an number:
CASE A WHEN 'stack' THEN 1 WHEN 'over' THEN 2 WHEN 'flow' THEN 3 END
and use it in your ORDER BY.
If you have alot of elements with custom ordering, you could add those elements to a table and give them a value. Join with the table and each column can have a custom order value.
select
main.a,
main.b,
main.c
from dbo.tblMain main
left join tblOrder rank on rank.a = main.a
order by rank.OrderValue
If you have only 3 elements as suggested in your question, you could use a case in the order by...
select
*
from dbo.tblMain
order by case
when a='stack' then 1
when a='flow' then 2
when a='over' then 3
else 4
end