Database Peer to peer relationship - sql

I have a table case which has case Id case Name
caseId | CaseName
------ |---------
1 | Case 1
-------|-------
2 |Case2
-------|-------
3 |Case 3
-------|-------
4 |Case 4
I have a requirement where all these cases are related, something like this:-
1-2
1-3
1-4
2-3
2-4
3-4
How to store the records in an efficient way

Make another table. Case Id and Related Case Id columns should have same data type as Case Id in your first table.
Case Id Related Case Id
1 4
2 4
2 3

Since it is a many to many relation, you can create a junction table with both columns as a foreign key to case.
case_relation (case_id_1, case_id_2). Something like this.

If caseId column have unique values
with t( caseId )as (
select 1 from dual union all
select 2 from dual union all
select 3 from dual union all
select 4 from dual
)
select t1.caseId, t2.caseId from t t1
cross join t t2
where
t1.caseId < t2.caseId

Related

One query that matches values with only one condition out of two, one query that matches values with both conditions

I'm having some sort of a blank about how to do this in SQL.
Consider this reprex in R
set.seed(123)
data.frame(ID = (sample(c(1:5), 10, replace = T)),
status = (sample(c("yes", "no"), 10, replace = T)),
amount = (sample(seq(1,50,0.01),10)))
which gives out this table
ID status amount
1 3 no 29.87
2 3 yes 26.66
3 2 yes 15.49
4 2 yes 18.89
5 3 yes 44.06
6 5 no 30.79
7 4 yes 17.13
8 1 yes 6.54
9 2 yes 45.68
10 3 yes 12.66
I need to find two SQL queries.
One where I select the ID's that only have status of 'NO'
meaning ID 5.
and
One where I select the ID's that match both conditions, meaning ID 3
I have a query for both but I'm almost sure it's not correct so any lead is more than welcome.
Thanks
One where I select the ID's that only have status of 'NO' meaning ID 5.
select id from your_table where status='no' and id not in (select id from
your_table where status='yes')
One where I select the ID's that match both conditions, meaning ID 3
select id from your_table where status='no' and id in (select id from
your_table where status='yes')
At last I think you are expecting ids which do not match these conditions. so UNION both queries and get ids of your table which not exists after UNION
select id from your_table where id not in (
select id from your_table where status='no' and id not in
(select id from your_table where status='yes')
union all
select id from your_table where status='no' and id in
(select id from your_table where status='yes')
)

How to replace subquery with in statement in bigquery

I happen to stumble with a problem using bigquery, I have to build a query where I need to limit the number of ids within the left join to a subset of a query, unfortunately bigquery does not support subquery.
I've been trying to find a solution that will allow me to place this constraint within the join but haven't been successful usually the solution I encounter suggest the usage of crossjoin but I haven't had success with it so far, here is in a nutshell the table structure I have and the query I'm trying to construct:
#standardSQL
WITH User AS (
SELECT 1 AS id, "A" AS items UNION ALL
SELECT 2 AS id, "B" AS items UNION ALL
SELECT 3 AS id, "c" AS items),
Label_User AS (
SELECT 1 AS user_id, 1 AS label_id UNION ALL
SELECT 1 AS user_id, 4 AS label_id UNION ALL
SELECT 1 AS user_id, 3 AS label_id UNION ALL
SELECT 2 AS user_id, 1 AS label_id UNION ALL
SELECT 2 AS user_id, 2 AS label_id),
Labels AS (
SELECT 1 AS id, "Test" AS label UNION ALL
SELECT 2 AS id, "Admin" AS label UNION ALL
SELECT 3 AS id, "Local" AS label UNION ALL
SELECT 4 AS id, "External" AS label)
select * from User left join Label_User on id=user_id and
label_id in (select id from Labels where label = "External" or label ="Local")
-- This works for a single record of label id
-- select * from User left join Label_User on id=user_id and label_id = 1
Any help would be very appreciated.
Edit 1
Thanks #mikhail-berlyant for his suggestion, but the issue I've found with having the condition in the where clause, it's that it filters out some records that I need, so the result I'm looking for looks like this:
id items user_id label_id
1 A 1 4
1 A 1 3
2 B null null
3 C null null
But having the filter in the where output this:
Row id items user_id label_id
1 A 1 4
1 A 1 3
Below is for BigQuery Standard SQL
#standardSQL
SELECT *
FROM User
LEFT JOIN (
SELECT *
FROM User
LEFT JOIN Label_User
ON id = user_id
WHERE label_id IN (SELECT id FROM Labels WHERE label = "External" OR label ="Local")
)
USING (id, items)
when applied t sample data from your question - output as below
Row id items user_id label_id
1 1 A 1 4
2 1 A 1 3
3 2 B null null
4 3 C null null

Select unique subsets

I have a table like in example below.
SQL> select * from test;
ID PARENT_ID NAME
1 1 A
2 1 B
3 2 A
4 2 B
5 3 A
6 3 B
7 3 C
8 4 A
What I need is to get all unique subsets of names ((A,B), (A,B,C), (A)) or exclude duplicate subsets. You can see that (A,B) is twice there, one for PARENT_ID=1 and one for 2.
I want to exclude such duplicates:
ID PARENT_ID NAME
1 1 A
2 1 B
5 3 A
6 3 B
7 3 C
8 4 A
You can use DISTINCT to only return different values.
e.g.
SELECT DISTINCT GROUP_CONCAT(NAME SEPARATOR ',') as subsets
FROM TABLE_1
GROUP BY PARENT_ID;
SQL Fiddle
I have used 'group_concat' assuming you are using 'Mysql'. The equivalent function in Oracle is 'listagg()'. you can see it in action here in SQL fiddle
Here is the solution:-
Select a.* from
test a
inner join
(
Select nm, min(parent_id) as p_id
from
(
Select Parent_id, group_concat(NAME) as nm
from test
group by Parent_ID
) a
group by nm
)b
on a.Parent_id=b.p_id
order by parent_id, name

PL/SQL Comparing Tables

I have task of matching candidates in my database with suitable job vacancies based on skill and availability, using sql and pl/sql only.
I have managed to write the following code which matches available candidates to available vacancies.
DECLARE
CURSOR availableCandidates_cur IS
SELECT * FROM candidate
WHERE candidate.available = 'True';
CURSOR availableJobs_cur IS
SELECT *
FROM position WHERE status = 'Open';
BEGIN
DBMS_OUTPUT.PUT_LINE('Available Candidates with matching vacencies');
FOR availableCandidates_rec IN availableCandidates_cur
LOOP
DBMS_OUTPUT.PUT_LINE('Candidate: ' || availableCandidates_rec.firstName || ' ' || availableCandidates_rec.lastName);
FOR availableJobs_rec IN availableJobs_cur
LOOP
IF (availableCandidates_rec.positionType = availableJobs_rec.positionType) THEN
DBMS_OUTPUT.PUT_LINE(availableJobs_rec.positionName);
END IF;
END LOOP;
END LOOP;
END;
I am struggling to figure out how to now match candidates to positions based on matching skills. The tables in question are
candidateSkills
candidateID | skillID
1 | 2
1 | 3
2 | 1
3 | 1
3 | 3
positionSkills
positionID | skillID
1 | 1
1 | 3
2 | 1
3 | 2
3 | 3
So for example i would like to output that
Candidate 1 Matches
position 3
Candidate 2 Matches
position 2
Candidate 3 Matches
position 2
position 3
I fear i may have gone down the wrong path intially which has lead to my confusion.
I would appreciate if someone could help steer me in the right direction.
Thanks
Corrected. Candidate 3 matches jobs 1 and 2, candidate 2 matches job 2, candidate 1 matches job 3
select distinct c.cid, j.jid
from candidate c, jobs j
where j.sid=c.sid
and not exists
(select 'x' from jobs j2 where j2.jid=j.jid
and j2.sid not in (select c2.sid from candidate c2
where c2.cid=c.cid))
--All candidates that match every skill in a position
select distinct candidateID, positionID
from
(
--Match candidates and positions, count number of skills that match
select candidateID, positionID, skills_per_position
,count(*) over (partition by candidateID, positionID) matched_skills
from candidateSkills
inner join
(
--Number of skills per position
select positionID, skillID
,count(*) over (partition by positionID) skills_per_position
from positionSkills
where status = 'Open'
) positionSkills_with_count
on candidateSkills.skillID = positionSkills_with_count.skillID
where available = 'True'
)
where matched_skills = skills_per_position
order by candidateID, positionID;
Using these scripts to build the tables:
create table candidateSkills as
select 1 candidateid, 2 skillID, 'True' available from dual union all
select 1 candidateid, 3 skillID, 'True' available from dual union all
select 2 candidateid, 1 skillID, 'True' available from dual union all
select 3 candidateid, 1 skillID, 'True' available from dual union all
select 3 candidateid, 3 skillID, 'True' available from dual;
create table positionSkills as
select 1 positionID, 1 skillID, 'Open' status from dual union all
select 1 positionID, 3 skillID, 'Open' status from dual union all
select 2 positionID, 1 skillID, 'Open' status from dual union all
select 3 positionID, 2 skillID, 'Open' status from dual union all
select 3 positionID, 3 skillID, 'Open' status from dual;
However, my results are slightly different. Candidate 3 matches position 1 and 2, not 2 and 3. I hope this is just a typo in your example.
Also, I didn't format my output exactly like yours. It can be a bit tricky to have SQL to display results in a multi-line format. However, leaving the SQL unformatted will also make it more useful if you want to use it in some other process.

SQL Server - How to display most recent records based on dates in two tables

I have 2 tables. I Want to list the records based on the recent date. For ex: from the following tables, I want to display ID 2 and ID 4 using a select statement. ID 2 and 4 are the most recent based on the dates from the second table. Please help me with the query. Thank you.
ID EXID PID REASON
1 1 1 XYZ
2 2 1 ABX
3 3 2 NNN
4 4 2 AAA
EXID EXDATE
1 1/1/2011
2 4/1/2011
3 3/1/2011
4 5/1/2011
Here you go, this ought to do it. Let me know if you have any questions.
SELECT
TBL.ID,
TBL.EXDATE
FROM
(
SELECT
T1.ID,
T2.EXDATE,
ROW_NUMBER() OVER(PARTITION BY T1.PID ORDER BY T2.EXDATE DESC) AS 'RN'
FROM
Table1 T1
INNER JOIN Table2 T2
ON T1.EXID = T2.EXID
) TBL
WHERE
TBL.RN = 1