SQL comparing each row to a reference row - sql

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

Related

COUNT vs SELECT in SQL

What is better approach to check existence of an object in database?
select count(id) as count from my_table where name="searchedName";
OR
select id from my_table where name="searchedName";
And then check if count > 0 or the object is not null (ORM logic)
EDIT:
select id to be valid for Oracle.
The idea should be to that we only need to find one record in order to say that such record exists. This can be done with an EXISTS clause in standard SQL.
select exists (select * from mytable where name = 'searchedName');
returns true if the table contains a record with 'searchedName' and false otherwise.
If you want 0 for false and 1 for true instead (e.g. if the DBMS does not support booleans):
select case when exists (select * from mytable where name = 'searchedName')
then 1 else 0 end as does_exist;
You say you want this for Oracle. In Oracle you can use above query, but you'd have to select from the table dual:
select case when exists (select * from mytable where name = 'searchedName')
then 1 else 0 end as does_exist
from dual;
But for Oracle we'd usually use rownum instead:
select count(*) as does_exist
from mytable
where name = 'searchedName'
and rownum = 1; -- to find one record suffices and we'd stop then
This also returns 1 if the table contains a record with 'searchedName' and 0 otherwise. This is a very typical way in Oracle to limit lookups and the query is very readable (in my opinion).
I'd just call:
select id from my_table where name='searchedName';
Making sure there is an index for the name column.
And then check whether or not the result is empty.
Try with IF EXISTS (
if exists (select 1 from my_table where name = "searchedName")
begin
....
end

SQL AND Clause only if another value exists

I have a basic SQL query where I am selecting data from a core records table. I want to add an AND clause to my statement to filter out the results based on a table variable, only if data actually exists in there.
SELECT
*
FROM
TABLE
WHERE
field = '123'
AND
(gender IN (SELECT gender FROM #genders))
In this case, I am looking for all records where field = 123. My goal here is to say that if #genders contains records, filter by that as well.
However, if #genders is empty and we don't have any data in it, it should include all records.
How can I go about doing this? The temp tables are created based on the user selecting one or more optional pieces of criteria from the UI. If they choose a gender for example, I put their selections into a temp table and then I need to search records that meet that criteria. However, if they don't select a gender, I want to include all records, regardless of what the main record has for the gender field.
SELECT
*
FROM
TABLE
WHERE
field = '123'
AND ((SELECT count(1) FROM #genders) = 0 OR
(gender IN (SELECT gender FROM #genders)))
You can use IF condition:
IF EXISTS(SELECT gender FROM #genders)
BEGIN
SELECT * FROM TABLE
WHERE field = '123'
AND
(gender IN (SELECT gender FROM #genders))
END
ELSE
BEGIN
SELECT * FROM TABLE
END
You are going to think this is odd but it is efficient
SELECT t.*
FROM TABLE t
JOIN GENDERS g
on g.gender = t.gender
and t.field = '123'
union all
SELECT t.*
FROM TABLE t
where not exists (select 1 from genders)
Maybe I'm under-thinking it, but isn't it just this?
SELECT
*
FROM
TABLE AS t
LEFT JOIN
#genders AS g
ON
g.gender = t.gender
WHERE
field = '123'
AND
(g.gender = t.gender OR g.gender IS NULL);
If your query doesn't get too complicated, I'd recommend an if statement. Once you find yourself continually adding if else statement in there, I'd recommend looking into dynamic SQL.
IF EXISTS(SELECT gender FROM #genders)
BEGIN
SELECT * FROM TABLE
WHERE field = '123'
and gender IN (SELECT distinct gender FROM #genders)
END
ELSE
BEGIN
SELECT * FROM TABLE WHERE field = '123'
END

Oracle SQL Joining 2 Queries

I am trying to form a query using 2 other queries, but I don't know how I would do it exactly. I am using Oracle SQL. Here is the basic logic:
if (select supervisor_id from PS_EMPLOYEES where EMPLID = %This.sEMPLID)
is in
(select EMPLID from sysadm.PS_Z_RPT_TO_REL where Z_DIRECT_RPT = 'D' where manager_id = %EmployeeID)
return True else return False.
Basically the first query will have an ID and will search through a list formed from the second query. If the ID from the first query is in the list from the second query then return 'True' else return 'False' Any thoughts?
Something like the following perhaps (untested):
SELECT EXISTS (
SELECT supervisor_id
FROM PS_EMPLOYEES
WHERE EMPLID = %This.sEMPLID
AND supervisor_id IN (
SELECT EMPLID
FROM sysadm.PS_Z_RPT_TO_REL
WHERE Z_DIRECT_RPT = 'D'
AND manager_id LIKE %EmployeeID
)
)

Select an ID if count is equal to 1

I am trying to write a query which needs to find an ID number from 3 WHERE values based on the result only being equal to 1.
So say i want to find a patient's ID and my where clause matches the firstname, lastname and DOB. If there are 2 results because of duplicates, i need the output to be NIL else it should return the patient ID.
if(select count(*)
from patient
where last_name = 'JAMES'
and first_name = 'JONES'
and birth_DtTM = '1980-01-01') > 1
print 'NULL' else return Pat_ID1
This is kind of what i am leading towards.
Thanks guys
select case when count(*)> 1
then 'NULL' else Pat_ID1 end
from patient
where last_name = 'JAMES'
and first_name = 'JONES'
and birth_DtTM = '1980-01-01'
group by Pat_ID1
try below.
;WITH CTE(Pat_ID1,last_name,first_name,birth_DtTM,dup_rows)
as
(
SELECT Pat_ID1,last_name,first_name,birth_DtTM,ROW_NUMBER() OVER(PARTITION BY last_name,first_name,birth_DtTM ORDER BY Pat_ID1) AS dup_rows FROM patient
)
SELECT
case when dup_rows>1 then null
when dup_rows=1 then Pat_ID1
end
FROM CTE
You can do it like this:
SELECT
PatientID = CASE COUNT(*) WHEN 1 THEN MAX(Pat_ID1) END
FROM
patient
WHERE
last_name = 'JAMES'
AND first_name = 'JONES'
AND birth_DtTM = '1980-01-01'
;
The CASE expression will evaluate either to the single Pat_ID1 matching the request or to NULL (if COUNT(*) is anything but 1).
As you can see, the Pat_ID1 value is obtained with the help of an aggregate function (by the way, you can use MIN instead of MAX just as well). This is because the presence of COUNT(*) in the query automatically implies grouping and now, if you want to reference columns of the underlying row set, you must only access their aggregated values.

Adjust SQL Query to force a record to appear first?

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))