SQL query on parents and relations - sql

so, recently i attended an interview where they asked the question like this,
there are 2 tables with parents and id in 1 table and relations between the id's on the 2nd table and we need to output based on the relations table the name of child father and mother .
input table parents:
id name
1 yogi
2 sidda
4 arpitha
5 sushma
6 navya
7 divya
8 sanju
9 ashwin
10 chetu
11 seena
12 vindi
input table relations:
child_id parent_id
4 1
4 2
5 10
5 6
7 8
7 9
11 12
11 13
The SQL is
select child,p2.name1, from parents p2 join
( select p1.name1 as child,r1.p_id,r1.c_id,p1.id1 from parents p1 join (select * from parents join relations on p_id=id1) r1 on p1.id1=r1.c_id) r2 on p2.id1=p_id;
which is giving me outlook like:
child parents
arpita yogi
arpita sidda
sushma chetu
sushma navya
divya sanju
divya ashwin
seena vindi
seena varshini
My expected output is:
child father mother
arpitha yogi sidda
sushma chetu navya
divya sanju ashwin
seena vindi varshini
this looks a lot like normalization question.

Not a great interview question as there's no way to solidly differentiate between mother and father - it's setting up for failure. It seems the first name is the father consistently so an approach using row number in a CTE would work
WITH c AS (
SELECT
T1.name
,T2.p_id
,T3.name as p_name
,row_number() OVER(PARTITION BY T2.c_id ORDER BY T2.p_id) AS row_no
FROM
names T1
INNER JOIN link T2
ON T1.id = T2.c_id
LEFT OUTER JOIN names AS T3
ON T2.p_id = T3.id
)
SELECT
T1.name AS c_name
,IS_NULL(T2.p_name,'none') AS f_name
,IS_NULL(T3.p_name,'none') AS m_name
FROM
c AS T1
LEFT OUTER JOIN c AS T2
ON T1.name = T2.name AND T2.row_no = 1
LEFT OUTER JOIN c AS T3
ON T1.name = T3.name AND T3.row_no = 2

Related

How can i get Parent-Child relationship values to new table when Parent and Child are stored in same table

I have a SQL Server table with a structure as shown here:
Parent
Child
1
2
2
3
3
4
4
5
I want to display the details like this table
Parent
Child1
Child2
Child 3
Child 4
1
2
3
4
5
2
3
4
5
5
3
4
5
5
5
How can I construct my SQL query? It is easy when I get parent, and child1 but it hard with child 2
When I try to use:
INSERT INTO TABLE2 (CHILD2)
SELECT CHILD
FROM TABLE1, TABLE2
WHERE TABLE1.PARENT = TABLE2.CHILD1
I have a big database to practice this exercise, its about 225.000 entity then this scrip stuck on query execute. Sorry for my bad English, need help fast. Thank you all for read my question.
You can just LEFT JOIN the same table again and again
SELECT
t1.Parent,
Child1 = t1.Child,
Child2 = t2.Child,
Child3 = t3.Child,
Child4 = t4.Child
FROM YourTable t1
LEFT JOIN YourTable t2 ON t2.PARENT = t1.CHILD
LEFT JOIN YourTable t3 ON t3.PARENT = t2.CHILD
LEFT JOIN YourTable t4 ON t4.PARENT = t3.CHILD;

How to get Oracle to return unique results in a one to many relationship tables with a left join

I have a three tables
Table 1
Id Department
1 A
2 B
3 C
4 D
Table 2
Id DepartId Name
1 1 ABC
2 1 DEF
3 1 ASD
4 2 FGH
5 2 HJK
6 3 ZXC
Table 3
Id Depart Area
1 A pp
2 B
3 C nn
4 D oo
I need the result
Id Depart Name Area
1 A ABC pp
2 B FGH Null
3 C ZXC nn
4 D NULL oo
I need one matching entry from table 2 and table 3 to corresponding entry in the table 1
Do a left join to also get t1 rows without any reference in the t2 table. GROUP BY to get only 1 row per Department.
select t1.id, t1.Department, min(t2.Name)
from t1
left join t2 on t1.id = t2.DepartId
group by t1.id, t1.Department
I think I would do this with a correlated subquery:
select t1.*,
(select t2.name
from t2
where t1.id = t2.DepartId and rownum = 1
) as t2name
from t1;
This saves the overhead of an aggregation. An index on t2(DepartId, name) is optimal for this query.
by the way not the answer to your specific question but if instead of just one you want all the names you can use listagg
SELECT t1.id,
department,
LISTAGG (name, ',') WITHIN GROUP (ORDER BY name) names
FROM t1, t2
WHERE t1.id = t2.departId(+)
GROUP BY t1.id, department
ORDER BY 1
ID Department Names
1 A ABC,ASD,DEF
2 B FGH, HJK
3 C ZXC
4 D

Select the value of a sibling row that can only be found through a parent row in SQL Server

I only have 1 table called Posts with 5 columns (much like StackExchange Data Explorer)
Id, Score, PostTypeId, ParentId, AcceptedAnswerId
1 5 1 null 3
2 3 1 null 5
3 9 2 1 null
4 3 2 1 null
....
As you can see, the rows have two levels of hierarchy (Parents, Childs). Let's say I want to select the childs (PostTypeId = 2) and for each one I would like to left join the score of the sibling that is currently accepted by the parent. The accepted sibling Id can only be found in the AcceptedAnswerId column of the parent row. The parent row can be found through the ParentId of the child row I am selecting. Is there an elegant way to do this?
The expected results is the following
Id, Score, AcceptedScore
3 9 9
4 3 9
....
My attempt (although it doesn't work and hurts my eyes as well as my brain):
select top 50 a.Id, a.Score, b.Score as AcceptedScore
from Posts as a
left join (
select c.Score from Posts as c
where c.Id = (
select d.AcceptedAnswerId from Posts as d
where d.Id = a.ParentId
)
) as b
on b.ParentId = a.ParentId
where a.PostTypeId = 2
The error I'm getting:
The multi-part identifier "a.ParentId" could not be bound. Invalid column name 'ParentId'.
Here's one that works:
SELECT p1.Id, p1.Score, p3.Score AS AcceptedScore
FROM Posts p1 LEFT JOIN Posts p2
ON p1.ParentId = p2.Id LEFT JOIN Posts p3
ON p2.AcceptedAnswerId = p3.Id
WHERE p1.PostTypeId = 2
See the SQLFiddle

Joining a table thru another property of another table that is linked with id

Edit : I did a mistake the Invoices Table carry the transactionId
I have 3 tables :
Transactions Reconciliations Invoices
id num line transId id Code transId
-- --- ---- ------- -- ---- -------------
3 1 1 3 5 Code 5 3
6 1 2 6 9 Code 9 8
7 1 3 7 12 Code 12 11
8 2 1 8
12 2 2 12
10 3 1 10
11 3 2 11
and this Query :
select
t1.id -- transaction id
t2.num -- reconciliation number
t3.Code -- Invoice code
from Transactions t1
left outer join Reconciliations t2 on t2.transId = t1.id
left outer join Invoices t3 on t3.transId = t1.id
Giving the following result :
id num code
-- --- ----
3 1 Code 5
6 1 null
7 1 null
8 2 Code 9
12 2 null
10 3 null
11 3 Code 12
But what I want is this :
id num code
-- --- ----
3 1 Code 5
6 1 Code 5
7 1 Code 5
8 2 Code 9
12 2 Code 9
10 3 Code 12
11 3 Code 12
To put words on it when the linked Invoice table gives null I want to join on all the records from Reconciliations with the same Reconciliation number.
Edit : I would like the Code in invoices to be shared across all transactions that shares the same Reconciliation number
I have tried to do thru outer apply and sub query but I cannot figure out a way to achieve it. Have you any idea ?
The solution is to join to Reconciliations again before joining to Invoices:
select t.id, r.num, i.Code
from Transactions t
join Reconciliations r on r.transId = t.id
join Reconciliations r2 on r2.num = r.num
join Invoices i on i.transId = r2.transId
Note that the joins are now inner joins (requiring a match), and how you easily make the connection to the right Invoice via the shared Reconciliation.num value - using inner joins means you only get the invoice row that matches.
To see this query in action, execute it on SQLFiddle
Edit: To cater for missing invoices
Use left join to invoices, but you need a group by with max() to limit the joins to just one invoice per transaction (without the max() you get lots of extra rows with null Code):
select t.id, r.num, max(i.Code) as Code
from Transactions t
join Reconciliations r on r.transId = t.id
join Reconciliations r2 on r2.num = r.num
left join Invoices i on i.transId = r2.transId
group by t.id, r.num
To see this query in action, where I have invalidated invoice 12 from above fiddle, execute it on SQLFiddle
You seem to want to spread the InvoiceId in Transactions up to the next value.
Here is one method:
select t.*
(select top 1 InvoiceId
from Transactions t2
where t2.id <= t.id and t2.InvoiceId is not NULL
order by id desc
) as newInvoiceId
from transactions t;
You can then substitute this into your query:
select
t1.id -- transaction id
t2.num -- reconciliation number
t3.Code -- Invoice code
from (select t.*
(select top 1 InvoiceId
from Transactions t2
where t2.id <= t.id and t2.InvoiceId is not NULL
order by id desc
) as newInvoiceId
from transactions t
) t1
left outer join Reconciliations t2 on t2.transid = t1.id
left outer join Invoices t3 on t3.id = t1.transid ;

SQL Server - Using Join to show only entries from second table

I am using SQL Server
The data that I have is:
table1:
R_Time ID Q1
2012-02-26 14 8
2012-02-27 14 7
2012-02-27 15 8
2012-02-27 16 9
2012-02-27 11 10
2012-02-28 11 6
2012-02-28 14 10
2012-02-28 15 9
and
table2:
ID Supervisor
11 2
14 2
15 3
16 3
What i am trying to due is only show R_Time and Q1 Entries from table1 where table2 Supervisor is 3
I know I will somehow have to do a join but im not quite sure how to.
Thanks.
Description
You can use a inner join to get this done.
T-SQL INNER JOIN operator can be used in any FROM clause to combine records from two tables.
Sample
Select tbl1.R_Time, tbl1.Q1 from table1 tbl1
inner join table2 tbl2 on tbl2.Id = tbl1.Id
where tbl2.Supervisor = 3
More Information
T-SQL - Inner Join
hope it helps!
select t2.time
from table1 t1
inner join table2 t2
on t1.Id = t2.Id
where t2.Supervisor = 3
Yup, you need to do an inner join:
select
a.r_time, a.q1
from
table1 a (nolock)
inner join table2 b (nolock) on b.id = a.id
where
b.supervisor = 3