SQL Select Puzzle - sql

Ok..here's what I want to do. I've oversimplified the example below:-
I have a table (Table1) with references in like this:
Table1_ID (PK)
Table1_ID Description
There's another table (Table2):-
Table2_ID (PK)
Table2_LinkedID (FK)
Table2_Status <--value is "open" or "complete"
Table2_LinkedID is linked to Table1_ID.
Ok. Now I have three queries that I want to connect together. Here is what I need.
First query:-
SELECT * FROM Table1
This works fine.
I want to add two additional columns to the query. The first is the total number of records in Table2 where the foreign key equals the primary key of table1 (ie SELECT *).
The second will be a count of records where Table2_Status = 'completed'
Does this make sense?

select t1.Table1_ID,
t1.Table1_Description,
t2.TotalCount,
t2.CompletedCount
from Table1 t1
left outer join (
select Table2_LinkedID,
count(*) as TotalCount,
count(case when Table2_Status = 'completed' then 1 end) as CompletedCount
from Table2
group by Table2_LinkedID
) t2 on t1.Table1_ID = t2.Table2_LinkedID

SELECT t1.*,
(SELECT COUNT(*) FROM Table2 WHERE Table2_LinkedID = t1.ID) cntTotal,
(SELECT COUNT(*) FROM Table2 WHERE Table2_LinkedID = t1.ID AND Table2_Status = 'completed') cntCompleted
FROM Table1 t1
Make sure to have a proper index for the foreign key and for Table2_Status for best performance.

You can make a simple GROUP BY with aggregates:
SELECT
Table1.ID,
Table1.Description,
Count(Table2.ID) AS TotalT2,
Sum(CASE WHEN Table2.Status = 'completed' THEN 1 ELSE 0 END) AS CountOfCompleted
FROM Table1
LEFT JOIN Table2 ON Table2.LinkedID = Table1.ID
GROUP BY Table1.ID, Table1.Description

Will this work for you?
Query 1:
select a.ID
, count(1) as Table2_RecordCount
from Table1 a
inner join Table2 b on b.LinkedID = a.ID
group by a.ID
Query 2:
select a.ID
, count(1) as Table2_RecordCount
from Table1 a
inner join Table2 b on b.LinkedID = a.ID
where b.[Status] = 'completed'
group by a.ID

Related

SQL Query, how to get data from two tables

Table 1:
ID (unqiue), Name, Address
Table 2:
RecordId, ID (key of table 1), Child name
In one query, I want to retrieve all rows of Table 1 with one additional column which will be the count of all record in table 2 from ID (that is number of children for each ID in table 1). Can't figure out how to format a query to retrieve this data.
Simply Join and apply count
select T1.*, COUNT(T2.RECORDID)AS T2COUNT from Table1 T1
INNER JOIN TABLE2 T2 ON T1.ID= T2.ID
--LEFT JOIN TABLE2 T2 ON T1.ID= T2.ID --if you need 0 child records (from commets by #Cha)
GROUP BY T1.ID , T1.Name, T1.Address
The correct way of doing this will be with a OUTER JOIN:
SELECT a.ID, a.Name, a.Address, b.cnt
FROM Table1 a
LEFT OUTER JOIN
(SELECT ID, count(*) cnt from Table2 GROUP BY ID) b
ON a.ID = b.ID
The incorrect way will be with a help of a correlated sub-query:
SELECT a.ID, a.Name, a.Address,
(SELECT count(*) FROM Table2 b WHERE b.ID = a.ID) as cnt
FROM Table1 a
Here is a discussion about correlated subqueries vs OUTER JOINs, if you are interested
Group by table1 fields and count total records in table2:
here T1 alias of table1 and T2 alias of table2.
select T1.ID, T1.Name, T1.Address, count(T2.ID) as total_records
from table1 as T1
left outer join table2 as T2 on T2.ID=T1.ID
group by T1.ID, T1.Name, T1.Address

SQL LEFT JOIN with WHERE class

there are two tables TABLE1 and TABLE2 in TABLE1 there are records which does not exist in TABLE2 with left join below i wanted to query all records which are in TABLE1 if the record does not exist in table2 however.
Note: about WHERE class in my code that is required this is because, there can be several records in the name of 'IN PROGRESS' in TABLE2 with one record in the name of 'GRADUATED' i wanted to distinct records based on table 1 ID that if there is any record in the name of 'GRADUATE' it should show only that else it should show inprogress.
SELECT DISTINCT
TABLE1.ID,
TABLE2.TRAINING_STATUS_CHECK
FROM TABLE1
LEFT JOIN TABLE2
ON TABLE1.ID = TABLE2.FK_ID_CLASS
WHERE NOT EXISTS
(
SELECT DISTINCT
TABLE1.ID,
TABLE2.TRAINING_STATUS_CHECK
FROM TABLE1
LEFT JOIN TABLE2
ON TABLE1.ID = TABLE2.FK_ID_CLASS
WHERE TABLE2.TRAINING_STATUS_CHECK = 'GRADUATED')
OR TABLE2.TRAINING_STATUS_CHECK = 'GRADUATED'
I see some odds with your query:
exists part are not related with you main query. I think you need some relation
distinct in part not exists are not needed
You filter columns with the same conditions as filter main row set
As I understand you want to get all rows from table1 with state 'GRADUATED' int table2 and any row from table1 where rows in table2 are not exists or state not equal 'GRADUATED'
SELECT DISTINCT
t1.ID,
t2.TRAINING_STATUS_CHECK
FROM TABLE1 t1
LEFT JOIN TABLE2 t2 ON t1.ID = t2.FK_ID_CLASS
WHERE NOT EXISTS
(
SELECT NULL /*its not nesessary what you need*/
FROM TABLE1 sub_t1
JOIN TABLE2 sub_t2 ON sub_t1.ID = sub_t2.FK_ID_CLASS /* left join replaced to inner */
WHERE sub_t2.TRAINING_STATUS_CHECK = 'GRADUATED'
AND sub_t1.ID = t1.ID /*relation with outer query*/
)
OR t2.TRAINING_STATUS_CHECK = 'GRADUATED'
where the relatonship between tables does not exist - but only if the comparison involves rows in table that are not 'graduated' (I think)
SELECT DISTINCT
TABLE1.ID,
TABLE2.TRAINING_STATUS_CHECK
FROM TABLE1
LEFT JOIN TABLE2 ON TABLE1.ID = TABLE2.FK_ID_CLASS
AND TABLE2.TRAINING_STATUS_CHECK <> 'GRADUATED'
WHERE TABLE2.FK_ID_CLASS IS NULL
Not sure about your question but if you want all the records from table 1 who are not in table 2, you just have to do this :
SELECT TABLE1.ID
FROM TABLE1
LEFT JOIN TABLE2 ON TABLE1.ID = TABLE2.FK_ID_CLASS
WHERE TABLE2.FK_ID_CLASS IS NULL
Try this:
SELECT DISTINCT TABLE1.ID, TABLE2.TRAINING_STATUS_CHECK
FROM TABLE1
LEFT JOIN TABLE2
ON TABLE1.ID = TABLE2.FK_ID_CLASS
AND (NOT EXISTS (SELECT 1
FROM TABLE2 t
WHERE TABLE1.ID = t.FK_ID_CLASS
AND t.TRAINING_STATUS_CHECK = 'GRADUATED')
OR TABLE2.TRAINING_STATUS_CHECK = 'GRADUATED')
For the record, conditions on the right table of a LEFT JOIN need to be placed inside the ON() clause or the join will transfer into an INNER JOIN due to NULL comparison.
It seems to me you have three distinct cases that can be "ORed together" using UNION; personally I find keeping all three separated like this makes things much easier to read and understand:
--- ID with GRADUATED exists in TABLE2
( SELECT ID, 'GRADUATED' AS TRAINING_STATUS_CHECK
FROM TABLE1
INTERSECT
SELECT FK_ID_CLASS, 'GRADUATED'
FROM TABLE2
WHERE TRAINING_STATUS_CHECK = 'GRADUATED' )
UNION
--- ID without GRADUATED exists in TABLE2
( SELECT ID, 'IN PROGRESS'
FROM TABLE1
MINUS
SELECT FK_ID_CLASS, 'IN PROGRESS'
FROM TABLE2
WHERE TRAINING_STATUS_CHECK = 'GRADUATED' )
UNION
--- ID does not exist in TABLE2
( SELECT ID, '{{NONE}}'
FROM TABLE1
WHERE ID NOT IN ( SELECT FK_ID_CLASS FROM TABLE2 ) );

Join then Distinct Count

. I need to find only Employees that are type A. I know this can be done with a JOIN. Then I need to get a count of all distinct EMP_ID for each Region.Also note this will be done in Oracle
These are basic things, you need join and condition on the table containing type = 'A':
select count(distinct emp_id)
from table1 t1
join table2 t2 on t1.job_code = t2.job_code
where t2.type = 'A'
group by t1.region
Could use a CTE.
With someCte
as
(
Select * from table1 t1
Inner join table2 t2 on t1.Job_code = t2.Job_code
where t1.type like 'A' and t2.type like 'A'
)
select distinct emp_id from someCte

Optimizing a SELECT with sub SELECT query in Oracle

Select id,
(Select sum(totalpay)
from Table2 t
where t.id = a.id
and t.transamt > 0
and t.paydt BETWEEN TRUNC(sysdate-0-7) and TRUNC(sysdate-0-1)) As Pay
from Table1 a
In spite of having indexes on transamt, paydt and id, the cost of the sub-query on Table2 is very expensive and requires a FULL TABLE scan.
Can this sub-query be optimized in any other way?
Please help.
Select t.id,
sum(totalpay) as Pay
from Table2 t join Table1
Where t.id = Table1.id
and t.transamt > 0
and t.paydt BETWEEN TRUNC(sysdate-0-7) and TRUNC(sysdate-0-1)
group by t.id
Try this:
Select a.id,
pay.totalpay
from Table1 a
(Select t.id, sum(totalpay) totalpay
from Table2 t
where t.transamt > 0
and t.paydt BETWEEN TRUNC(sysdate-0-7) and TRUNC(sysdate-0-1)
group by t.id
) As Pay
where a.id = pay.id
push group by joining columns (id column in this example) into subquery to calculate results for all values in Table2 and then join with Table1 table.
In original query you calculate result for every crow from Table1 table reading full Table2 table.

Subquery with multiple select statements

to check the subquery having multiple select statement inside 'not in' condition
Eg.
select id from tbl where
id not in (select id from table1) and
id not in (select id from table2) and
id not in (select id from table3)
instead of repeating the same id 'not in' condition , i need the subquery which will check in one shot from multiple tables..
pls help..
Your query is better expressed as:
SELECT id
FROM tbl t
LEFT JOIN table1 t1 on t1.id = t.id
LEFT JOIN table2 t2 on t2.id = t.id
LEFT JOIN table3 t3 on t3.id = t.id
WHERE t1.id IS NULL AND t2.id IS NULL AND t3.id IS NULL
You could use a union, so you just have one in:
select id
from tbl
where id not in
(
select id from table1
union all select id from table2
union all select id from table3
)
Note: not in does not work well with nullable columns, but I assume id is not nullable here.
use union all
like this -->
select f.FIRST_NAME from farmer f where f.ID in (select v.ID from Village v where v.ID in (1,2) union all select s.ID from state s where s.ID in (3,4) )