SQL SELECT Ordering columns with Null Values - sql-server

My question is similar to this one: How to display a table order by code (like 01, 02… then null columns)?, but for SQL Server.
In short, I have a SELECT statement, that returns the following:
ColumnA ColumnB
X NULL
Y 1
Z 2
..where the ordering is done by ColumnB.
How can we force the (columnB = NULL) type of rows to the bottom? ie, the expected result is this:
ColumnA ColumnB
Y 1
Z 2
X NULL
Thank you SOF community.

...or in order to avoid value clashing...
SELECT
ColumnA,
ColumnB
FROM YourTable
ORDER BY
CASE WHEN ColumnB IS NULL THEN 1 ELSE 0 END ASC,
ColumnB

You can also use isnull:
select * from thetable order by isnull(columnb, 99999)
isnull will replace null with the value you provide to it, so in this case, if the column is null, it will replace it with 99999. You can set the value to some big number so it will be at the bottom of the order.

hoping to help someone,
I just wanted to add that I have had a similiar issue, using row_number and partition by -
when it is zero put it at the end sort of thing
and I used the script below (partial view):
,T.MONTHS_TO_AUTOGROWTH
,the_closest_event=ROW_NUMBER() OVER (PARTITION BY SERVERID, DRIVE ORDER BY
CASE WHEN MONTHS_TO_AUTOGROWTH > 0 THEN MONTHS_TO_AUTOGROWTH ELSE 9999
END )
the result is ordered by MONTHS_TO_AUTOGROWTH but zero comes last

Related

Can SQLite3 SELECT (up to) some rows based on a WHERE, and in the same query SELECT other rows on another condition?

Hi it's my first time using SQLite and I am trying to understand if it can count the results it gets and switch conditions to find other results: I am not sure how to write this, so I will use an example:
From a table of players, with the same query I'd like to:
SELECT (x) players WHERE WINS>0 AND WINS<= 3 and
(y) other players WHERE WINS = Null OR WINS=0.
x and y should be integer numbers, but they could vary.
I think I can split the query in 2 queries, but I am worried about the performance since in this way I have to connect to the db twice, and I have to check on the second query that the new IDs have not been selected already in the first one (this should never happen in this example scenario, but might happen with different conditions).
If it's possible to write this all in one single query, that would be much more "simple" and straightforward.
Unfortunately I have to stick to SQLite 3.7.17 and I can't make use of all the updates until now.
mytable is defined like this one:
CREATE TABLE mytable (
ID TEXT PRIMARY KEY,
NAME TEXT,
WINS INTEGER,
LOSSES INTEGER,
NOTES TEXT
);
These are some dummy values:
INSERT INTO mytable(ID, NAME, WINS,LOSSES, NOTES) VALUES
('A001','John','1','0','blue')
('A002','Mark','2','1','blue')
('A003','Hubert','null','null','red')
('A004','Otto','0','0','green')
('A005','Johnson','3','5','red')
('A006','Frank','null','1','green')
As an example result the query should return:
#first part (WINS>0 AND WINS<=3) x = 3
('A005','Johnson','3','5','red')
('A001','John','1','0','blue')
('A002','Mark','2','1','blue')
#second part(WINS=0 OR WINS=Null) y = 2
('A006','Frank','null','1','green')
('A004','Otto','0','0','green')
..so the result should be a table like that
('A005','Johnson','3','5','red')
('A001','John','1','0','blue')
('A002','Mark','2','1','blue')
('A006','Frank','null','1','green')
('A004','Otto','0','0','green')
Thank you for your time and knowledge. :)
Use a CTE where you filter the table for the conditions that you want to apply and with a CASE expression get an integer for the condition that is satisfied for each row.
In another CTE use ROW_NUMBER() window function to rank the rows of each condition.
Finally filter the rows with a CASE expression:
WITH
cond AS (
SELECT *,
CASE
WHEN WINS > 0 AND WINS <= 3 THEN 1
WHEN WINS IS NULL OR WINS = 0 THEN 2 -- or WHEN COALESCE(WINS, 0) = 0 THEN 2
END AS condition
FROM mytable
WHERE condition IN (1, 2)
),
cte AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY condition ORDER BY condition, WINS) rn FROM cond)
SELECT ID, NAME, WINS, LOSSES, NOTES
FROM cte
WHERE rn <= CASE condition
WHEN 1 THEN 3 -- x = 3
WHEN 2 THEN 2 -- y = 2
END
ORDER BY condition, WINS DESC;
See the demo.

TSQL ORDER BY with nulls first or last (at bottom or top)

I have a date column which has some NULL. I want to order by the date column ASC, but I need the NULL s to be at the bottom. How to do it on TSQL?
In standard SQL you can specify where to put nulls:
order by col asc nulls first
order by col asc nulls last
order by col desc nulls first
order by col desc nulls last
but T-SQL doesn't comply with the standard here. The order of NULLs depends on whether you sort ascending or descending in T-SQL:
order by col asc -- implies nulls first
order by col desc -- implies nulls last
With integers you could simply sort by the negatives:
order by -col asc -- sorts by +col desc, implies nulls first
order by -col desc -- sorts by +col asc, implies nulls last
But this is not possible with dates (or strings for that matter), so you must first sort by is null / is not null and only then by your column:
order by case when col is null then 1 else 2 end, col asc|desc -- i.e. nulls first
order by case when col is null then 2 else 1 end, col asc|desc -- i.e. nulls last
Select *
From YourTable
Order By case when DateCol is null then 0 else 1 end
,DateCol
Or even Order By IsNull(DateCol,'2525-12-31')
order by case when col_name is null then 1 else 2 end, col_name asc did the trick on Oracle. However the same on MS SQL Server pushes the NULL records down leaving non null to be on top of the result set.
This did the trick for me just now. Fortunately, I'm working with text. For anything numeric, I'd probably go with all 9's.
COALESCE(c.ScrubbedPath,'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'),
Sometimes, you may need to use a subquery to get this right:
select site_id, site_desc
from (
select null as site_id, 'null' as site_desc
union
select s.site_id,
s.site_code+'--'+s.site_description as site_desc
from site_master s with(nolock)
)x
order by (case when site_id is null then 0 else 1 end), site_desc

TSQL query optimizer view on non-nullable ISNULL()

As part of some dynamic SQL (ick), I've implemented the 'sort NULLs last' solution described here: Sorting null-data last in database query
ORDER BY CASE column WHEN NULL THEN 1 ELSE 0 END, column
My question is: On non-nullable columns that have ISNULL() applied to them, will the query optimizer strip this out when it realises that it will never apply?
It's not clear why your question mentions the ISNULL function when that isn't in your code.
ORDER BY CASE column WHEN NULL THEN 1 ELSE 0 END, column
First of all this code doesn't work, it is equivalent to CASE WHEN column = NULL which is not what you need.
It would need to be
ORDER BY CASE WHEN column IS NULL THEN 1 ELSE 0 END, column
The optimisation question is easy to test.
CREATE TABLE #T
(
X INT NOT NULL PRIMARY KEY
)
SELECT *
FROM #T
ORDER BY X
SELECT *
FROM #T
ORDER BY CASE WHEN X IS NULL THEN 1 ELSE 0 END, X
DROP TABLE #T
The plan shows a sort operation in the second plan indicating that this was not optimised out as you hoped and the pattern is less efficient than ORDER BY X.

Get the missing value in a sequence of numbers

I made the following query for the SQL Server backend
SELECT TOP(1) (v.rownum + 99)
FROM
(
SELECT incrementNo-99 as id, ROW_NUMBER() OVER (ORDER BY incrementNo) as rownum
FROM proposals
WHERE [year] = '12'
) as v
WHERE v.rownum <> v.id
ORDER BY v.rownum
to find the first unused proposal number.
(It's not about the lastrecord +1)
But I realized ROW_NUMBER is not supported in access.
I looked and I can't find something similar.
Does anyone know how to get the same result as a ROW_NUMBER in access?
Maybe there's a better way of doing this.
Actually people insert their proposal No (incrementID) with no constraint. This number looks like this 13-152. xx- is for the current year and the -xxx is the proposal number. The last 3 digits are supposed to be incremental but in some case maybe 10 times a year they have to skip some numbers. That's why I can't have the auto increment.
So I do this query so when they open the form, the default number is the first unused.
How it works:
Because the number starts at 100, I do -99 so it starts at 1.
Then I compare the row number with the id so it looks like this
ROW NUMBER | ID
1 1 (100)
2 2 (101)
3 3 (102)
4 5 (104)<--------- WRONG
5 6 (105)
So now I know that we skip 4. So I return (4 - 99) = 103
If there's a better way, I don't mind changing but I really like this query.
If there's really no other way and I can't simulate a row number in access, i will use the pass through query.
Thank you
From your question it appears that you are looking for a gap in a sequence of numbers, so:
SELECT b.akey, (
SELECT Top 1 akey
FROM table1 a
WHERE a.akey > b.akey) AS [next]
FROM table1 AS b
WHERE (
SELECT Top 1 akey
FROM table1 a
WHERE a.akey > b.akey) <> [b].[akey]+1
ORDER BY b.akey
Where table1 is the table and akey is the sequenced number.
SELECT T.Value, T.next -1 FROM (
SELECT b.Value , (
SELECT Top 1 Value
FROM tblSequence a
WHERE a.Value > b.Value) AS [next]
FROM tblSequence b
) T WHERE T.next <> T.Value +1

SQL SELECT Query

I have a very simple table that has businesses and a column of DisplayBiz = varchar(1) that is either Y or N... I want a script to extract data from the database first all the "Y" and then then all the "N" for a total of ten and I want them ordered by business name..
Is there a way to do this? I am assuming it would be something like this:
SELECT TOP 10 MemberID,
BizName
ORDER BY BizType
but this doesn't take into consideration the DisplayBiz column
Any ideas?
Many thanks..!
You can add more than one column in the ORDER BY clause :
-- ...
ORDER BY DisplayBiz DESC, BizType
Which would put Y rows first, then N rows.
This will get the first 10 alphabetical BizNames that have a 'Y' for DisplayBiz. If there are less than 10, it will start over at A for those with 'N'...
SELECT TOP 10 MemberID, BizName, DisplayBiz
FROM dbo.table
ORDER BY
CASE WHEN DisplayBiz = 'Y' THEN 1 ELSE 2 END,
BizName;
You could also use:
ORDER BY
DisplayBiz DESC,
BizName;
But I prefer the CASE - while more code, you're not taking advantage of the English spelling of Y/N. Seems more proper to be explicit.

Resources