SQL Server Compare two rows to identify ID - sql

Here is what I am trying to do.
I have one column of data that is the ID of every person. I have a second column of data that is the ID of just supervisors. I also have a third column of data that identifies an ID as staff or faculty.
I need to take the Supervisor column and compare it against the ID column. When the supervisor's ID is located then I need to identify that row as a staff of faculty supervisor in a separate column. If the ID is not in the supervisor column then they just need to be marked as staff or faculty based off of the third column.
So the three columns that I have are ID, Supervisor ID and Class Type.
Any help would be appreciated.
Here is the code that I currently have
select distinct ODS_PERSON.ID "Cient_ID",
ODS_PERSON.LAST_NAME "Last_Name",
CASE
WHEN H17_PERSON.NICKNAME is not null
THEN H17_PERSON.NICKNAME
ELSE ODS_PERSON.FIRST_NAME
END "First_Name",
H17_PERSON.H17_PER_USERNAME + '#highpoint.edu' "Email",
CASE
WHEN ODS_HRPER.HRP_EFFECT_TERM_DATE is null
THEN '1'
ELSE '0'
END "User_Status",
CASE
WHEN SPT_POSITION.POS_CLASS = 'FACL' AND (ODS_PERSON.ID = SPT_PERPOS.PERPOS_SUPERVISOR_HRP_ID)
THEN 'FACSUP'
ELSE 'NOPE'
END "Employee_Type",
SPT_PERPOS.PERPOS_SUPERVISOR_HRP_ID "Manager",
SPT_POSITION.DEPARTMENT_DESC "Department",
SPT_PERPOS.PERPOS_POS_SHORT_TITLE "Position_Title",
SPT_POSITION.POS_CLASS "Position_Class"
from ( ( ( ( ( SPT_PERPOSWG SPT_PERPOSWG left join ODS_HRPER ODS_HRPER on SPT_PERPOSWG.PPWG_HRP_ID = ODS_HRPER.HRPER_ID ) left join SPT_PERPOS SPT_PERPOS on SPT_PERPOSWG.PPWG_HRP_ID = SPT_PERPOS.PERPOS_HRP_ID ) left join SPT_PERSTAT SPT_PERSTAT on SPT_PERPOSWG.PPWG_HRP_ID = SPT_PERSTAT.PERSTAT_HRP_ID ) left join ODS_PERSON ODS_PERSON on SPT_PERPOSWG.PPWG_HRP_ID = ODS_PERSON.ID ) left join SPT_POSITION SPT_POSITION on SPT_PERPOS.PERPOS_POSITION_ID = SPT_POSITION.POSITION_ID ) left join H17_PERSON H17_PERSON on SPT_PERPOSWG.PPWG_HRP_ID = H17_PERSON.ID
where ODS_HRPER.HRP_EFFECT_TERM_DATE is null
and SPT_PERPOS.PERPOS_END_DATE is null
order by ODS_PERSON.ID

SELECT ID, Supervisor_ID, Class_Type,
CASE
WHEN SuperVisor_ID is null and Class_Type is not null THEN Class_Type
WHEN (SuperVisor_ID = ID or SuperVisor_ID is not null) THEN 'Supervisor'
END
from tableID
Not sure if this is what you're looking for. In the future it would be helpful to know how many tables are involved, and if the data types in each column can be compared directly or if you have to cast the data types.
You may also want to put whether join conditions are necessary to get the information and what columns the tables would join on.
Hope this helps

Related

Find values from table whose column value determines which column from another table to be used for lookup

I have 2 tables with no relationship defined at DDL.
CREATE TABLE SOURCES(
ID VARCHAR2(25),
SOURCE VARCHAR(2),
VALUE_ID(VARCHAR2(25),
LAST_UPDATED TIMESTAMP);
CREATE TABLE USERS(
ID VARCHAR2(25),
USER_ID VARCHAR(25),
CLIENT_ID VARCHAR(25));
I need to find all those rows from table sources given an input value for column VALUE_ID. VALUE_ID is set to USERS.USER_ID or USERS.CLIENT_ID based on the SOURCE column of that row.
IF SOURCE = 'A' THEN VALUED_ID = USERS.USER_ID ELSE USERS.CLIENT_ID
Any help resolving this would be much appreciated.
You can use a CASE statement in your join:
Select *
FROM SOURCES S
INNER JOIN USERS U
on S.Value_ID = CASE WHEN S.SOURCE='A' then U.USER_ID ELSE U.CLIENT_ID END
Just use AND and OR in the join condition:
SELECT *
FROM sources s
INNER JOIN users u
ON ( (s.source = 'A' AND s.value_id = u.user_id )
OR (s.source <> 'A' AND s.value_id = u.client_id))

Referential integrity between tables in SQL Server

I have 2 tables, Members and Enrollments. Both tables can be joined using primary key Member ID.
I need to write a query which returns all the members in the Members table which don't have a corresponding row in the Enrollments table and vice versa.
This is what I have so far:
IF OBJECT_ID('tempdb..#memberswithoutenrollments') IS NOT NULL
DROP TABLE #memberswithoutenrollments
SELECT m.*
INTO #memberswithoutenrollments
FROM ABC_Members m
LEFT OUTER JOIN ABC_MemEnrollment e ON m.MemberID = MemberID
FULL JOIN is a simple method for comparing lists between two tables:
SELECT COALESCE(e.MemberID, m.MemberID),
(CASE WHEN e.MemberID IS NULL THEN 'No Enrollments' ELSE 'No Member' END)
FROM ABC_Members m FULL JOIN
ABC_MemEnrollment e
ON m.MemberID = e.MemberID
WHERE e.MemberID IS NULL OR m.MemberID IS NULL;
But if you have proper foreign key relationships, then you should never have enrollments without members.
You can use NOT IN to your benefit here.
WITH
-- Create a list of all of the matches
in_table AS
(
SELECT
Member_ID
FROM
Enrollments
WHERE
Members.MemberID = Enrollments.Member_ID
),
result_table AS
(
SELECT
*
FROM
Members
-- Grab only the values from members that DO NOT APPEAR in in_table
WHERE
MemberID NOT IN (SELECT DISTINCT FROM in_table)
)
-- Grab all results
SELECT * FROM result_table

joining a table on 2 fields

I want to pull a person and their supervisor names from a table. The persons table has the supervisor_id and the person_id. The names table has name_id and a Full Name field. If I join Person ON either supervisor_id or person_id, how do I get the other to display as well?
You need to join twice, one for each relationship you have:
SELECT
-- Persons' columns
P.*,
-- Superviser name columns
SN.*,
-- Person name columns
PN.*
FROM
persons AS P
LEFT JOIN names AS SN ON P.supervisor_id = SN.name_id
LEFT JOIN names AS PN ON P.person_id = PN.name_id
Or you can join with an OR clause, but you won't be able to know which record did you join with unless you check with a CASE.
SELECT
-- Persons' columns
P.*,
-- name columns
N.*,
IsSupervisor = CASE WHEN P.supervisor_id = N.name_id THEN 'Yes' ELSE 'No' END
FROM
persons AS P
LEFT JOIN names AS N ON
P.supervisor_id = N.name_id OR
P.person_id = N.name_id
This last approach will display 2 rows as it will match either one or the other on different occasions, not both with the same persons row (as the first example).
A (self)join is what you need:
select p.*, supervisor=ps.name
from Person p join person ps on p.supervisor_id=ps.id

How to work in case in join condition

How to find city when ContactID is provided and condition is if ContactID is coming as 123 then it will look whether it is P or C, If P then it will go to Person table and returns City(USA) as output and If C then it will go to Company table and gives City(AUS) as output.
NB: all tables contain thousands of record and City value comes from run time.
Unless you're dynamically generating the query (i.e. using some language other than SQL to execute it) then you need to join on both tables anyway. If you're joining on both tables then there's no need for a CASE statement:
select *
from contacts co
left outer join person p
on co.contactid = p.contactid
and co.person_company = 'P'
left outer join company c
on co.contactid = c.contactid
and co.person_company = 'C'
You'll start noting an issue here, for every column from PERSON and COMPANY you're going to have to add some business logic to work out which table you want the information from. This can get very tiresome
select co.contactid
, case when p.id is not null then p.name else c.name end as name
from contacts co
left outer join person p
on co.contactid = p.contactid
and co.person_company = 'P'
left outer join company c
on co.contactid = c.contactid
and co.person_company = 'C'
Your PERSON and COMPANY tables seem to have exactly the same information in them. If this is true in your actual data model then there's no need to split them up. You make the determination as to whether each entity is a person or a company in your CONTACTS table.
Creating additional tables to store data in this manner is only really helpful if you need to store additional data. Even then, I'd still put the data that means the same thing for a person or a companny (i.e. name or address) in a single table.
If there's a 1-2-1 relationship between CONTACTID and PID and CONTACTID and CID, which is what your sample data implies, then you have a number of additional IDs, which have no value.
Lastly, if you're not restricting that only companies can go in the COMPANY table and individuals in the PERSON table. You need the PERSON_COMPANY column to exist in both PERSON and COMPANY, though as a fixed string. It would be more normal to set up this data model as something like the following:
create table contacts (
id integer not null
, contact_type char(1) not null
, name varchar2(4000) not null
, city varchar2(3)
, constraint pk_contacts primary key (id)
, constraints uk_contacts unique (id, contact_type)
);
create table people (
id integer not null
, contact_type char(1) not null
, some_extra_info varchar2(4000)
, constraint pk_people primary key (id)
, constraint fk_people_contacts
foreign key (id, contact_type)
references contacts (id, contact_type)
, constraint chk_people_type check (contact_type = 'P')
);
etc.
you can LEFT JOIN all 3 tables and the using a CASE statement select the one that you need based on the P or C value
SELECT
CASE c.[Person/Company]
WHEN 'P' THEN p.NAME
WHEN 'C' THEN a.Name
END AS Name
FROM Contact c
LEFT JOIN Person p on p.ContactId = c.ContactId
LEFT JOIN Company a on a.ContachId = c.ContactId
Ben's answer is almost right. You might want to check that the first join has no match before doing the second one:
select c.*, coalesce(p.name, c.name) as p.name
from contacts c left outer join
person p
on c.contactid = p.contactid and
c.person_company = 'P' left join
company co
on c.contactid = co.contactid and
c.person_company = 'C' and
p.contactid is null;
This may not be important in your case. But in the event that the second join matches multiple rows and the first matches a single row, you might not want the additional rows in the output.

SELECT Statement in CASE

Please don't downgrade this as it is bit complex for me to explain. I'm working on data migration so some of the structures look weird because it was designed by someone like that.
For ex, I have a table Person with PersonID and PersonName as columns. I have duplicates in the table.
I have Details table where I have PersonName stored in a column. This PersonName may or may not exist in the Person table. I need to retrieve PersonID from the matching records otherwise put some hardcode value in PersonID.
I can't write below query because PersonName is duplicated in Person Table, this join doubles the rows if there is a matching record due to join.
SELECT d.Fields, PersonID
FROM Details d
JOIN Person p ON d.PersonName = p.PersonName
The below query works but I don't know how to replace "NULL" with some value I want in place of NULL
SELECT d.Fields, (SELECT TOP 1 PersonID FROM Person where PersonName = d.PersonName )
FROM Details d
So, there are some PersonNames in the Details table which are not existent in Person table. How do I write CASE WHEN in this case?
I tried below but it didn't work
SELECT d.Fields,
CASE WHEN (SELECT TOP 1 PersonID
FROM Person
WHERE PersonName = d.PersonName) = null
THEN 123
ELSE (SELECT TOP 1 PersonID
FROM Person
WHERE PersonName = d.PersonName) END Name
FROM Details d
This query is still showing the same output as 2nd query. Please advise me on this. Let me know, if I'm unclear anywhere. Thanks
well.. I figured I can put ISNULL on top of SELECT to make it work.
SELECT d.Fields,
ISNULL(SELECT TOP 1 p.PersonID
FROM Person p where p.PersonName = d.PersonName, 124) id
FROM Details d
A simple left outer join to pull back all persons with an optional match on the details table should work with a case statement to get your desired result.
SELECT
*
FROM
(
SELECT
Instance=ROW_NUMBER() OVER (PARTITION BY PersonName),
PersonID=CASE WHEN d.PersonName IS NULL THEN 'XXXX' ELSE p.PersonID END,
d.Fields
FROM
Person p
LEFT OUTER JOIN Details d on d.PersonName=p.PersonName
)AS X
WHERE
Instance=1
Ooh goody, a chance to use two LEFT JOINs. The first will list the IDs where they exist, and insert a default otherwise; the second will eliminate the duplicates.
SELECT d.Fields, ISNULL(p1.PersonID, 123)
FROM Details d
LEFT JOIN Person p1 ON d.PersonName = p1.PersonName
LEFT JOIN Person p2 ON p2.PersonName = p1.PersonName
AND p2.PersonID < p1.PersonID
WHERE p2.PersonID IS NULL
You could use common table expressions to build up the missing datasets, i.e. your complete Person table, then join that to your Detail table as follows;
declare #n int;
-- set your default PersonID here;
set #n = 123;
-- Make sure previous SQL statement is terminated with semilcolon for with clause to parse successfully.
-- First build our unique list of names from table Detail.
with cteUniqueDetailPerson
(
[PersonName]
)
as
(
select distinct [PersonName]
from [Details]
)
-- Second get unique Person entries and record the most recent PersonID value as the active Person.
, cteUniquePersonPerson
(
[PersonID]
, [PersonName]
)
as
(
select
max([PersonID]) -- if you wanted the original Person record instead of the last, change this to min.
, [PersonName]
from [Person]
group by [PersonName]
)
-- Third join unique datasets to get the PersonID when there is a match, otherwise use our default id #n.
-- NB, this would also include records when a Person exists with no Detail rows (they are filtered out with the final inner join)
, cteSudoPerson
(
[PersonID]
, [PersonName]
)
as
(
select
coalesce(upp.[PersonID],#n) as [PersonID]
coalesce(upp.[PersonName],udp.[PersonName]) as [PersonName]
from cteUniquePersonPerson upp
full outer join cteUniqueDetailPerson udp
on udp.[PersonName] = p.[PersonName]
)
-- Fourth, join detail to the sudo person table that includes either the original ID or our default ID.
select
d.[Fields]
, sp.[PersonID]
from [Details] d
inner join cteSudoPerson sp
on sp.[PersonName] = d.[PersonName];