I ran into an old code in an application. ORDER BY is not working here. From the execution plan, it looks like the ORDER BY is not executed at all.
IF(1 = 1)
(
SELECT * FROM dbo.Table WHERE Column1= 'abc'
)
ELSE
(
SELECT * FROM dbo.Table
)
ORDER BY Column2
I know I can get it to work by refactoring this query like this.
But I am just curious why the ORDER BY is not getting executed in the above query at the first place.
IF(1 = 1)
BEGIN
SELECT * FROM dbo.Table WHERE Column1= 'abc' ORDER BY Column2
END
ELSE
BEGIN
SELECT * FROM dbo.Table ORDER BY Column2
END
The ORDER BY is working, but only for the ELSE clause. SQL Server allows this syntax:
(SELECT * FROM dbo.Table )
ORDER BY Column2
And that is how the code is being interpreted. The ORDER BY is part of the ELSE. And I should point out that the IF condition is true, so it is the THEN query that is being executed.
You can do a UNION ALL instead of the IF:
SELECT * FROM dbo.Table WHERE 1 = 1 AND Column1= 'abc'
UNION ALL
SELECT * FROM dbo.Table WHERE NOT (1 = 1)
ORDER BY Column2
(Not here, but IF condition null values might need to be handled
too.)
Related
How can I write WHERE cluase so it returns rows that meet the criteria, if there are no such records it should return all records from a table?
Using UNION ALL:
select t.* from table t where condition
union all
select t.* from table t cross join (select count(*) cnt from table where condition) c
where c.cnt=0
Or (much more efficiently):
select col1, col2, ... colN
from
(
select t.*, sum(case when condition then 1 else 0 end) over() cnt from table
) s
where condition or s.cnt=0
Replace condition with your WHERE condition
One method you could consider in t-sql is to use ##rowcount to determine if you need to return all rows.
The benefit of doing so is you get two separate execution plans, one only optimised for your first exists criteria and would be beneficial if the majority of results are where the exists condition is met.
select <columns>
from <table>
where <condition>
if ##rowcount=0
begin
select <columns>
from <table>
end
One way would be:
SELECT *
FROM Person
WHERE
Name = 'John'
OR NOT EXISTS(SELECT null FROM Person WHERE Name = 'John')
I don't like it, for all those good reasons mentioned in the comments. If I was handed this requirement as part of a system I was creating I'd probably examine the need for the requirement; selecting all rows from a table is seldom useful if it's the sort of table that you query with a criteria: "Dear user, we couldn't find your person named John so here are the other 4.27 billion users in the system, pagination size 100"
that satisfies me enough:
WHERE (
ISNULL(#variable, '') = ''
OR #variable = [Column]
)
Not exactly what I described above but it returns all the records if condition is not met. However in that case condition would be assigning a value to variable.
1st method
Where ( ISNULL(#Param,'')='' OR ColumnName = #Param)
2nd way
WHERE ( ColumnName =CASE WHEN #Param IS NULL THEN ColumnName
ELSE #Param
END)
3rd way
WHERE (#Param ='' OR #Param =ColumnName)
I would recommend a CTE with not exists:
with cte as (
select t.*
from t
where . . .
)
select *
from cte
union all
select *
from t
where not exists (select 1 from cte);
I have been trying to construct a conditional IN like below, but this gives me the scalar subquery produced more than one element error. How should I approach this type of query instead? The tables are not related.
select * from my_table
where my_table.my_col in (
case
when 1 = 1
then (select my_col from my_other_table_1)
else (select my_col from my_other_table_2)
end
)
Try this below-
select * from my_table
where my_table.my_col in (
SELECT
case
when 1 = 1 then my_col_1
else my_col_2
END
from my_other_table
)
As your other tables are not related, you can try this below logic-
select * from my_table
where
(1=1 and my_col IN (select my_col_1 from my_other_table_01)
OR
(3=3 and my_col IN (select my_col_2 from my_other_table_02)
I need to get a maximum of 3 distinct records from the same table, so currently I'm doing:
SELECT 1, mycolumn FROM mytable WHERE id = #firstId
UNION ALL
SELECT 2, mycolumn FROM mytable WHERE id = #secondId
UNION ALL
SELECT 3, mycolumn FROM mytable WHERE id = #thirdId
The actual SELECT part contains over 20 columns and the FROM part contains a number of JOINs. The first column is a constant and is always fixed depending on the record. I don't know how many records might return. It could be anything from 0 to 3 records.
Is it possible to change the above query so that it uses IN like this:
SELECT ???, mycolumn FROM mytable WHERE id IN (#firstId, #secondId, #thirdId)
But how do I explicitly map each record to the fixed constant if I use IN?
You may use a CASE expression here with a single query:
SELECT
CASE id WHEN #firstId THEN 1
WHEN #secondId THEN 2
WHEN #thirdId THEN 3 END AS val,
mycolumn
FROM mytable
WHERE
id IN (#firstId, #secondId, #thirdId);
If you wish to also order by the computed column, then add ORDER BY val to the end of the above query.
You can use CASE like following.
SELECT
CASE
WHEN id= #firstId THEN 1
WHEN id=#secondId THEN 2
ELSE 3
END AS rn,
mycolumn
FROM mytable
WHERE id IN (#firstId,
#secondId,
#thirdId)
Another approach can be using DENSE_RANK if you have one record for each provided id and #firstId, #secondId & #thirdId are in ascending order.
SELECT DENSE_RANK()
OVER(
ORDER BY id) rn,
mycolumn
FROM mytable
WHERE id IN ( #firstId, #secondId, #thirdId )
I would recommend a table-valued constructor for this purpose:
select v.outputnum, my_column
from mytable t join
(values (#firstid, 1),
(#secondid, 2),
(#thirdid, 3)
) v(id, outputnum)
on t.id = v.id
order by v.outputnum;
I think this is simpler than other versions, because the list of ids is only present once in the query -- so no danger of different parts of the query getting out of sync.
say i have a TABLE with the values
1,2,2,3,4 and ALL
in the SAME column
and I then
SELECT DISTINCT
value
FROM table
How would I go about always selecting 'All' 1st ?
or atleast ordering it that 'All' is 1st.
NOTE: The column is a VARCHAR(x)
EDIT:
SELECT DISTINCT
Strategy
FROM #Strategy
ORDER BY case when Strategy = 'All' then 0 else 1 end,
Strategy DESC
This is my query currently
You chose correct keyword (DISTINCT) and correct expression (ORDER BY CASE WHEN ... END) for each individual question. The trick is to solve the questions one by one instead of once.
SELECT *
FROM
(
SELECT DISTINCT T1.*
FROM (VALUES ('1'), ('2'), ('2'), ('3'), ('4'), ('ALL')) AS T1(Strategy)
) AS T2
ORDER BY CASE WHEN Strategy = 'ALL' THEN 0 ELSE 1 END, Strategy;
In this instance just use:
SELECT DISTINCT Value FROM TABLE ORDER BY Value Desc
Please try this.
Declare #table table (id varchar(max))
Insert into #table values ('1'),('2'),('2'),('All'),('3'),('4')
select * from #table
--select * from #table order by id
select * from #table order by case when id = 'All' then 0 else id end
Another twist, suppose you have 2 varchar entry still this logic work as
Declare #table table (id varchar(max))
Insert into #table values ('1'),('2'),('2'),('All'),('3'),('4'),('Select')
select * from #table
select * from #table order by id
select * from #table order by case when id in ( 'All' , 'Select') then 0 else id end
You can use GROUP BY (instead of DISTINCT) with #jarlh 's suggestion for the ORDER BY clause in the comments above (tweaked ever so slightly).
SELECT
Strategy
FROM
#Strategy
GROUP BY
Strategy
ORDER BY
CASE WHEN Strategy = 'All' THEN 0 ELSE Strategy END
Or by continuing to use DISTINCT you can move the CASE statement to the SELECT clause to create a new column to use in the ORDER BY clause:
SELECT DISTINCT
Strategy
,CASE WHEN Strategy = 'All' THEN 0 ELSE Strategy END AS SortOrder
FROM
#Strategy
ORDER BY
SortOrder
Or if the order of the subsequent items doesn't matter just keep it simple as #ChrisChurch suggests.
i need your help to insert into from select but my query is too complex for me. My logic is below
INSERT INTO TheTable(A,CustomerNo,item,B,C,D)
SELECT DISTINCT
case when ((select count(*) from hesap where CustomerNo=e.CustomerNo)0) then
select top 1, A,CustomerNo,item+1,B,C,D
from dbo.Table1 order by ekno desc
) else select 100,e.CustomerNo,e.item,0,e.defterid,'C'
from Table2 e end
But i can not do that...
You can do case on column basis only.
What you can do is UNIONing two selects, and insert the result. Something like
INSERT INTO TheTable(A,CustomerNo,item,B,C,D)
SELECT ...
WHERE (select count(*) from hesap where CustomerNo=e.CustomerNo) = 0
UNION
SELECT select 100,e.CustomerNo,e.item,0,e.defterid,'C'
WHERE (select count(*) from hesap where CustomerNo=e.CustomerNo) > 0
I'm sorry, I cannot always follow your Select, but I hope you got the idea. You have to separate the 2 possibilities before you UNION them, so only 1 row can exist for each original row.
Can you try removing the comma after top 1 Like this:
INSERT INTO TheTable(A,CustomerNo,item,B,C,D)
SELECT DISTINCT
case when ((select count(*) from hesap where CustomerNo=e.CustomerNo)0) then
select top(1) A,CustomerNo,item+1,B,C,D
from dbo.Table1 order by ekno desc
)
else select 100,e.CustomerNo,e.item,0,e.defterid,'C'
from Table2 e end