Adjust SQL Query to force a record to appear first? - sql

How can the below query be adjusted to return always the member with MemberID = 'xxx' as the first row
SELECT * FROM Members

select * from Members
order by case when MemberID = XXX then 0 else 1 end

This should work and it will also allow you to order the remaining items by MemberID (Assuming xxx=12 in this example)
SELECT *
FROM Members
ORDER BY CASE WHEN MemberID=12 THEN NULL ELSE isnull(MemberID,0) END
If the memberID column can't contain nulls, you can get away with this which might perform slightly better.
SELECT *
FROM Members
ORDER BY CASE WHEN MemberID=12 THEN NULL ELSE MemberID END

SELECT
CASE WHEN MemberID = 'xxx' AS 1 ELSE 0 END CASE AS magic,
*
FROM Members
ORDER BY magic DESC
The syntax might vary depending on yr db, but I hope you get the idea.

SELECT * FROM `Members` WHERE `MemberID` = '[ID]' LIMIT 1 UNION SELECT * FROM `Members`
This should work. Tested on my database instance. Chosen ID is always first.

A more robust solution, if you have more than one record that has to be floated to the top, or if you have a specific order for multiple records, is to add a ResultsOrder column to your table, or even another table MemberOrder(memberid, resultorder). Fill resultorder with big numbers and ...
Select m.*
From Members m
Left Join MemberOrder mo on m.MemberID=mo.MemberID
Order by coalesce(mo.resultorder, 0) DESC

try this:
SELECT * FROM Members
ORDER BY IF(x.MemberId = XXX, -1, ABS(x.MemberId))

Related

SQL Select row depending on values in different columns

I've already found so many answers here but now I can't seem to find any to my specific problem.
I can't figure out how to select a value from a row depending on the value in different columns
with the below table, I want to achieve the following results.
in case the value in column stdvpuni = 1 then return values / contents from this row for the article (column art).
in case the value in column stdvpuni = 0 then return values / contents from the row where STDUNIABG = 1 for this article (column art).
You seem to want one row part art, based on the content of other rows. That suggests using row_number():
select t.*
from (select t.*,
row_number() over (partition by art order by stdvpuni desc, STDUNIABG desc) as seqnum
from t
) t
where seqnum = 1;
You don't specify what to do if neither column is 1. You might want a where clause (where 1 in (stdvpuni, STDUNIABG)) or another condition in the order by.
I do not know what values / contents is, but I suppose that's easy for you to figure out. So, I will focus on the way to select this:
SELECT
CASE
WHEN current.stdvpuni = 1 THEN 'values / contents of current row'
ELSE 'values / contents of other row'
END
FROM yourtable current
JOIN yourtable other
ON other.stdvpuni = 1;
Use your conditions with NOT EXISTS in the WHERE clause:
SELECT t1.*
FROM tablename t1
WHERE t1.STDVPUNI = 1
OR (
t1.STDVPUNI = 0 AND t1.STDUNIABG = 1
AND NOT EXISTS (SELECT 1 FROM tablename t2 WHERE t2.ART = t1.ART AND t2.STDVPUNI = 1)
);

SQL comparing each row to a reference row

I am trying to compare each row from a select statement to a reference row.
So to put it into context I would like to find the reference row which is the account details for one of our users.
SELECT id, first_name
FROM account
WHERE id = '100'
Would return the info for the user in question
Then I want to run a SELECT statement to return all users - pretty straightforward
SELECT id,first_name
FROM account
For each row I would like to compare the first_name with the reference row. If it is the same return a '1' if it is different return a '0'
I can do this if I type in the value to compare e.g 'Paul'
SELECT id,first_name,
CASE
WHEN first_name = 'Paul' THEN '1'
ELSE '0'
END
FROM account
But obviously I want to replace Paul with whatever the first_name is from the reference row above.
My googling suggests I need to declare a variable and then something with SELECT INTO a variable
DO $$;
Declare
#reference_first_name text;
BEGIN
SELECT first_name
into #reference_first_name
FROM account
WHERE id = ‘100’
END;
But I can't seem to put it together.
Then to go a step further would it be possible to reference multiple columns?
You could do this simply in a subquery:
demo:db<>fiddle
SELECT
id,
first_name,
CASE
WHEN (SELECT first_name FROM users WHERE id = 100) = first_name THEN 1
ELSE 0
END
FROM users;
Other ways are using a CTE or a JOIN (see fiddle for these versions)
Here's another option using an outer join:
select a.id, a.first_name, case when a.first_name = b.first_name then 1 else 0 end
from account a
left join account b on b.id = 100
Online Demo
Use correlated subquery as :
select a.id, a.first_name,
( select count(*)
from personnel p
where p.id = 100
and upper(p.first_name) = upper(a.first_name) ) as flag
from account a;
provided you have a table called personnel and has an ID fixed for all comparisons.
Rextester Demo

Assign null if subquery retrieves multiple records. How can it be done?

I have the following query. I simplified it for demo purpose. I am using SQL Server - t-sql
Select tm.LocID = (select LocID from tblLoc tl
where tl.LocID = tm.LodID )
from tblMain tm
if the subquery returns multiple records, I like to assign tm.LocID to null else if there is only 1 record returned then assign it to tm.LocID. I am looking for a simple way to do this. Any help would be appreciated.
One way I can see is to have a CASE statement and check if (Count * > 1 ) then assign null else return the value but that would require a select statement within a select statement.
You have the right idea about using a case expression for count(*), but it will not require another subquery:
SELECT tm.LocID = (SELECT CASE COUNT(*) WHEN 1 THEN MAX(LocID) END
FROM tblLoc tl
WHERE tl.LocID = tm.LodID )
FROM tblMain tm
or just use a HAVING clause, like
Select tm.LocID = (select LocID from tblLoc tl
where tl.LocID = tm.LodID
group by locID
having count(*) = 1)
)
from tblMain tm
Your query above (and many of the other answers here) is a correlated subquery which will be very slow since it performs a separate aggregation query on each record. This following will address both your problem and potentially perform a bit better since the count happens in a single pass.
SELECT
CASE
WHEN x.locid IS NOT NULL THEN x.locid
ELSE NULL
END
FROM tblMain m
LEFT JOIN (
SELECT
locid
FROM tblLoc
GROUP BY locid
HAVING COUNT(1) = 1
) x
ON x.locid = m.locid
;
The above is in Postgres syntax (what I'm familiar with) so you would have to make it TSQL compatible.

Select Case is not working with Order by

I was using a simple sql query and getting an ordered list, but when I changed some of the values in the column I'm sorting by, those rows were no longer being sorted correctly.
select distinct u.Email,
case
when l.region_id is null then 'EU'
else l.region_id
end
as Location
from TB_User u
left join cat..location l on l.location=u.Location
where u.Username in (....)
order by l.region_id
I have about 5 rows that returned null for their region_id so they would be at the top of the result set. When I added the case and replaced their value, they still remain at the top. Is there anyway to make these rows sort according to their given value?
You can use CASE also in the ORDER BY. But in this case it seems that you instead want to order by the column which uses the CASE.
ORDER BY Location
If you instead want the null-regions at the bottom:
ORDER BY CASE WHEN l.region_id is null THEN 0 ELSE 1 END DESC,
Location ASC
If your rdbms doesn't support this (like SQL-Server does) you have to repeat it:
ORDER BY CASE WHEN l.region_id IS NULL THEN 'EU' ELSE l.region_id END ASC
You just order by the column value, which is null.
If you want to order by the case statement, just copy it in the order by clause:
order by
case
when l.region_id is null then 'EU'
else l.region_id end
If you are using SQL, try within the SELECT statement, use:
ISNULL(l.region_id, 'EU') AS Location
and then
ORDER BY 2
This will make your query:
SELECT DISTINCT u.Email, ISNULL(l.region_id, 'EU') AS Location
FROM TB_User u
LEFT JOIN cat..location l ON l.location=u.Location
WHERE u.Username in (....)
ORDER BY 2

Order by Maximum condition match

Please help me to create a select query which contains 10 'where' clause and the order should be like that:
the results should be displayed in order of most keywords(where conditions) matched down to least matched.
NOTE: all 10 condition are with "OR".
Please help me to create this query.
i am using ms-sql server 2005
Like:
Select *
from employee
where empid in (1,2,4,332,434)
or empname like 'raj%'
or city = 'jodhpur'
or salary >5000
In above query all those record which matches maximum conditions should be on top and less matching condition record should be at bottom.
SELECT *
FROM (SELECT (CASE WHEN cond1 THEN 1 ELSE 0 END +
CASE WHEN cond2 THEN 1 ELSE 0 END +
CASE WHEN cond2 THEN 1 ELSE 0 END +
...
CASE WHEN cond10 THEN 1 ELSE 0 END
) AS numMatches,
other_columns...
FROM mytable
) xxx
WHERE numMatches > 0
ORDER BY numMatches DESC
EDIT: This answer was posted before the question was modified with a concrete example. Marcelo's solution addresses the actual problem. On the other hand, my answer was giving priority to matches of specific fields.
You may want to try something like the following, using the same expressions in the ORDER BY clause as in your WHERE clause:
SELECT *
FROM your_table
WHERE field_1 = 100 OR
field_2 = 200 OR
field_3 = 300
ORDER BY field_1 = 100 DESC,
field_2 = 200 DESC,
field_3 = 300 DESC;
I've recently answered a similar question on Stack Overflow which you might be interested in checking out:
Is there a SQL technique for ordering by matching multiple criteria?
There are many options/answers possible. Best answer depends on size of the data, non-functional requirements, etc.
That said, what I would do is something like this (easy to read / debug):
Select * from
(Select *, iif(condition1 = bla, 1, 0) as match1, ..... , match1+match2...+match10 as totalmatchscore from sourcetable
where
condition1 = bla or
condition2 = bla2
....) as helperquery
order by helperquery.totalmatchscore desc
I could not get this to work for me on Oracle.
If using oracle, then this Order by Maximum condition match is a good solution.
Utilizes the case when language feature