How to get fields from multiple tables - sql

I want to get fields from 2 different tables . The last field candidate_score_id has a many to one relationship. So how should I join the below 2 queries
1) To get candidate_score_id from the candidate_score table.
select candidate_score_id from candidate_score a where
a.assessment_id = NEW.assessment_id and
a.candidate_id = NEW.candidate_id and
a.attempt_Count = NEW.attempt_count;
2) To insert different fields in to the candidate_score_details table. The field in this table should be obtained by query above.
insert into candidate_score_details(candidate_score_details_id, candidate_id, assessment_id, attempt_count, score_type, score_tag,correct, candidate_score_id)
select uuid();
select a.candidate_id, a.assessment_id,a.attempt_count,"BY-COMPLEXITY",
case c.complexity
when 1 then "HIGH"
when 2 then "MEDIUM"
when 3 then "LOW"
end, count(*) from candidate_answer a, answer_key b, question_meta_data c where a.candidate_id = NEW.candidate_id and
a.assessment_id = NEW.assessment_id and
a.attempt_count = NEW.attempt_count and
a.assessment_id = b.assessment_id and
a.question_id = b.question_number and
a.response = b.answer and
a.question_id = c.question_number
group by a.candidate_id, a.assessment_id, a.attempt_count, c.complexity;

Just looking at the SQL joining aspect of your question, you'll need to specify the table I THINK you're aliasing a 2nd table with the "NEW" reference. If that's the case, then the query would be (replacing "OTHER_TABLE_NAME" with the name of the 2nd table:
select a.candidate_score_id
from candidate_score a
left join OTHER_TABLE_NAME new on
and a.assessment_id = NEW.assessment_id
and a.candidate_id = NEW.candidate_id
and a.attempt_Count = NEW.attempt_count

Seems that Query 1 has the same 3 criteria on the "candidate_score" table as for the "candidate_answer" table in Query 2.
So how about adding a LEFT JOIN of "candidate_score" to "candidate_answer" on those 3 fields?
For example:
INSERT INTO candidate_score_details
(
candidate_score_details_id,
candidate_id,
assessment_id,
attempt_count,
score_type,
score_tag,
correct,
candidate_score_id
)
SELECT
uuid(),
answer.candidate_id,
answer.assessment_id,
answer.attempt_count,
'BY-COMPLEXITY' AS score_type,
(CASE meta.complexity
WHEN 1 THEN 'HIGH'
WHEN 2 THEN 'MEDIUM'
WHEN 3 THEN 'LOW'
END) AS score_tag,
COUNT(*) AS correct,
MAX(score.candidate_score_id) AS max_candidate_score_id
FROM candidate_answer AS answer
JOIN answer_key AS akey
ON (akey.assessment_id = answer.assessment_id AND akey.question_number = answer.question_id AND akey.answer = answer.response)
LEFT JOIN candidate_score AS score
ON (score.candidate_id = answer.candidate_id AND score.assessment_id = answer.assessment_id AND score.attempt_count = answer.attempt_count)
LEFT JOIN question_meta_data AS meta
ON meta.question_number = answer.question_id
WHERE answer.candidate_id = NEW.candidate_id
AND answer.assessment_id = NEW.assessment_id
AND answer.attempt_count = NEW.attempt_count
GROUP BY answer.candidate_id, answer.assessment_id, answer.attempt_count, meta.complexity;

Related

Postgresql: Query using multiple attributes

I'm trying to create a query with Postgresql. Unfortunately, the attributes in the attribute_table are listed as rows instead of columns which makes it harder to pull. I want to pull a count based on the three attributes I have listed below (1000 = gender - 2 = female, 1001 = age group - 5 = 55-64, 1002 = household size = 1). How do I adjust this query so that it only gives me one row vs three rows of the same personal_ID? Also when I use this query, it doesn't pull any values but if I put only 1 attribute it works.
select sa.country_id ,count(distinct sa.personal_id )
from study_table sa ,attribute_table a
where sa.country_id =a.country_id and sa.personal_id =a.personal_id
and to_char(sa.mailing_date,'yyyy-MM')='2021-01'
and attribute_id =1000 and a.attribute_number =2
and attribute_id =1001 and a.attribute_number =5
and attribute_id =1002 and a.attribute_number =1
and study_type ='Wave'
and status not in ('NEW','EXCLUDED','ERROR')
group by sa.country_id
First, use proper, explicit, standard JOIN syntax.
Second, your WHERE conditions are contradictory. You need ORs . . . and then a HAVING for the final filtering:
select sa.country_id ,count(distinct sa.personal_id )
from study_table sa join
attribute_table a
on sa.country_id = a.country_id and
sa.personal_id = a.personal_id
where to_char(sa.mailing_date,'yyyy-MM') = '2021-01' and
( (attribute_id = 1000 and a.attribute_number = 2) or
(attribute_id = 1001 and a.attribute_number = 5) or
(attribute_id = 1002 and a.attribute_number = 1)
) and
study_type ='Wave'
status not in ('NEW','EXCLUDED','ERROR')
group by sa.country_id
having count(distinct attribute_id) = 3;
It seems your attribute_table follows an Entity-Attribute-Value. (IMHO that is an extremely bad bad plan - but if that is what you got that is what you deal with). So to get/validate/set 3 attributes you need to reference that table 3 times in the query -once for each attribute.
select sa.country_id
, count(distinct sa.personal_id )
from study_table sa
join ( select g.personal_id
from attribute_table g
join attribute_table ag on ag.personal_id = ag.personal_id
join attribute_table hs on hs.personal_id = hs.personal_id
where 1=1
and (g.attribute_id =1000 and g.attribute_number =2)
and (ag.attribute_id =1001 and ag.attribute_number =5)
and (hs.attribute_id =1002 and hs.attribute_number =1)
) sf
on sf.personal_id = sa.personal_id
where 1=1
and to_char(sa.mailing_date,'yyyy-mm')='2021-01'
and sa.study_type ='Wave'
and sa.status not in ('NEW','EXCLUDED','ERROR')
group by sa.country_id;
The above of course assumes the column names study_type and status originate in the study table - seems likely.
But if not you will need 2 more references to the attribute table.
Hint: Always use tables aliases on ALL column references.

T-SQL Full Outer Join (sample provided)

I have some issues getting a full outer join to work in T-SQL. The left outer join part seems to be working okay, but the right outer join doesn't work as expected. Here's some sample data to test this on:
I have a table A with the following columns and data. The row marked with red is the row that cannot be found in table B.
And a second table B with the following columns and data. The rows marked with yellow are the rows that cannot be found in table A.
I am trying to join the tables using the following sql code:
select tableA.klientnr, tableA.uttakstype, tableA.uttaksnr, tableA.vareanr TableAItem,tableB.vareanr tableBitem, tableA.kvantum tableAquantity, tableB.totkvant tableBquantity
from tableA as tableA
full outer join tableB as tableB on tableA.klientnr=tableB.klientnr and tableA.uttakstype=tableB.uttakstype and tableA.uttaksnr=tableB.uttaksnr and tableA.vareanr=tableB.vareanr and tableB.IsDeleted=0
where tableA.UttaksNr=639779 and tableA.IsDeleted=0
The result of the sql is the following image. The row marked in red is the extra row from tableA that does show up, but I can't get the rows from table B to show up
Expected to have 2 extra rows
550 SA 639779 NULL 100059 NULL 0
550 SA 639779 NULL 103040 NULL 14
Later edit:
Would this be correct way to handle the full outer join where there's the header/line type of structure? Or can the query be optimized?
SELECT ISNULL(q1.accountid, q2.accountid) AccountId
,ISNULL(q1.klientnr, q2.klientnr) KlientNr
,ISNULL(q1.tilgangstype, q2.tilgangstype) 'Reception Type'
,ISNULL(q1.tilgangsnr, q2.tilgangsnr) 'Reception No'
,ISNULL(q1.dato, q2.dato) dato
,ISNULL(q1.LevNr, q2.LevNr) LevNr
,ISNULL(q1.Pakkemerke, q2.Pakkemerke) Pakkemerke
,ISNULL(q1.VareANr, q2.VareANr) VareANr
,ISNULL(q1.Ankomstdato,q2.Ankomstdato) 'Arrival Date'
,q1.Antall1
,q1.totkvant1
,q1.Antall2
,q1.totkvant2
,q2.Antall
,q2.totkvant
,q2.AntallTilFrys
,q2.TotKvantTilFrys
,ISNULL(q1.EksternKommentar1,q2.EksternKommentar1) EksternKommentar1
,q2.[Last Upsert]
FROM (
SELECT w700.accountid
,w700.klientnr
,w700.tilgangstype
,w700.tilgangsnr
,w700.dato
,w700.Ankomstdato
,w700.LevNr
,w700.pakkemerke
,w789.VareANr
,sum(IIF(w789.prognosetype = 1, w789.Antall, NULL)) AS Antall1
,sum(IIF(w789.prognosetype = 1, w789.totkvant, NULL)) AS totkvant1
,sum(IIF(w789.prognosetype = 2, w789.Antall, NULL)) AS Antall2
,sum(IIF(w789.prognosetype = 2, w789.totkvant, NULL)) AS totkvant2
,w700.EksternKommentar1
FROM trading.W789Prognosekjopstat AS w789
INNER JOIN trading.W700Tilgangshode AS w700 ON w700.AccountId = w789.AccountId
AND w700.KlientNr = w789.Klientnr
AND w700.Tilgangsnr = w789.Tilgangsnr
AND w700.Tilgangstype = w789.Tilgangstype
AND w700.IsDeleted = 0
WHERE w789.IsDeleted = 0
GROUP BY w700.accountid
,w700.klientnr
,w700.tilgangstype
,w700.tilgangsnr
,w700.dato
,w700.Ankomstdato
,w700.LevNr
,w700.pakkemerke
,w789.VareANr
,w700.EksternKommentar1
) q1
FULL OUTER JOIN (
SELECT w700.accountid
,w700.klientnr
,w700.tilgangstype
,w700.tilgangsnr
,w700.dato
,w700.Ankomstdato
,w700.LevNr
,w700.pakkemerke
,w702.VareANr
,w702.Antall
,w702.TotKvant
,w702.ValPris
,w702.AntallTilFrys
,w702.TotKvantTilFrys
,w700.EksternKommentar1
,(SELECT MAX(LastUpdateDate) FROM (VALUES (w702.createdAt),(w702.updatedAt)) AS UpdateDate(LastUpdateDate)) AS 'Last Upsert'
FROM trading.w702PrognoseKjop w702
INNER JOIN trading.W700Tilgangshode AS w700 ON w700.AccountId = w702.AccountId
AND w700.KlientNr = w702.Klientnr
AND w700.Tilgangsnr = w702.Tilgangsnr
AND w700.Tilgangstype = w702.Tilgangstype
AND w700.IsDeleted = 0
WHERE w702.IsDeleted = 0
) q2 ON q1.accountid = q2.accountid
AND q1.klientnr = q2.klientnr
AND q1.tilgangstype = q2.tilgangstype
AND q1.tilgangsnr = q2.tilgangsnr
AND q1.vareanr = q2.vareanr
WHERE totkvant1 IS NOT NULL
OR totkvant2 IS NOT NULL
OR totkvant IS NOT NULL
Filtering with full join is really tricky. Your where criteria are actually turning the full join into a left join.
You can do what you want by filtering before the join:
select a.klientnr, a.uttakstype, a.uttaksnr, a.vareanr a.tableAitem,
b.vareanr b.tableBitem, a.kvantum a.tableAquantity, b.totkvant b.tableBquantity
from (select a.*
from tableA a
where a.UttaksNr = 639779 and a.IsDeleted = 0
) a full join
(select b.*
from tableB b
where b.IsDeleted = 0
) b
on a.klientnr = b.klientnr and
a.uttakstype= b.uttakstype and
a.uttaksnr = b.uttaksnr and
a.vareanr = b.vareanr;

SQL subquery filter using parent table fields

I have a query as below:
SELECT tr.AccountFK ,
TransactionRequestStatus = CASE
WHEN tr.TransactionRequestStatusFK = 2 THEN 'Accepted'
ELSE 'Rejected'
END,
tr.TransactionRequestID
FROM [CRM].[acc].[TransactionRequest] as tr
INNER JOIN CRM.acc.TransactionRequestHistory as trh
ON tr.TransactionRequestID = trh.TransactionRequestFK
where tr.TransactionRequestTypeFK = 3 --bill split
and TransactionRequestStatusFK in (2, 3) --Approved, Rejected
--Filter- on each item
and (tr.TransactionRequestStatusFK = 2 and tr.TransactionRequestID not in (select tr.TransactionRequestID from crm.acc.TransactionRequest tr
INNER JOIN CRM.acc.TransactionRequestHistory as trh
ON tr.TransactionRequestID = trh.TransactionRequestFK
where tr.TransactionRequestID = trh.TransactionRequestFK
and trh.EventFK = 15)
or
tr.TransactionRequestStatusFK = 3 and tr.Notes not like '%No Action%')
group by tr.AccountFK, tr.TransactionRequestStatusFK, tr.TransactionRequestID
I have a subquery in the where clause to apply a filter on each item but this subquery join is the same has the join in the main query, is there any way to re-use the main query table and avoid repeating same code in the subquery.
Using CTE. Assuming the column names in both crm.acc.TransactionRequest and CRM.acc.TransactionRequestHistory are distinct, the following should work. If they aren't, then you'll have to specify the columns with their alias in the Select of cte.
with cte as
(select * from crm.acc.TransactionRequest tr
INNER JOIN CRM.acc.TransactionRequestHistory as trh
ON tr.TransactionRequestID = trh.TransactionRequestFK)
SELECT AccountFK ,
TransactionRequestStatus = CASE
WHEN TransactionRequestStatusFK = 2 THEN 'Accepted'
ELSE 'Rejected'
END,
TransactionRequestID
FROM cte
where TransactionRequestTypeFK = 3 --bill split
and TransactionRequestStatusFK in (2, 3) --Approved, Rejected
--Filter- on each item
and (TransactionRequestStatusFK = 2 and TransactionRequestID not in
(select TransactionRequestID from cte
where TransactionRequestID = TransactionRequestFK
and EventFK = 15)
or
TransactionRequestStatusFK = 3 and Notes not like '%No Action%')
group by AccountFK, TransactionRequestStatusFK, TransactionRequestID

Return a Count of 0 When No Rows

OK, I've looked this up and tried a number of solutions, but can't get it to work. I'm a bit of a novice. Here's my original query - how can I get it to return 0 for an account when there are no results in the student table?
SELECT a.NAME
,count(s.student_sid)
FROM account a
JOIN inst i ON a.inst_sid = i.root_inst_sid
JOIN inst_year iy ON i.inst_sid = iy.inst_sid
JOIN student s ON iy.inst_year_sid = s.inst_year_sid
WHERE s.demo = 0
AND s.STATE = 1
AND i.STATE = 1
AND iy.year_sid = 16
AND a.account_sid IN (
20187987
,20188576
,20188755
,52317128
,20189249
)
GROUP BY a.NAME;
Use an outer join, moving the condition on that table into the join:
select a.name, count(s.student_sid)
from account a
join inst i on a.inst_sid = i.root_inst_sid
join inst_year iy on i.inst_sid = iy.inst_sid
left join student s on iy.inst_year_sid = s.inst_year_sid
and s.demo = 0
and s.state = 1
where i.state = 1
and iy.year_sid = 16
and a.account_sid in (20187987, 20188576, 20188755, 52317128, 20189249)
group by a.name;
count() does not count null values, which s.student_sid will be if no rows join from student.
You need to LEFT JOIN and then SUM() over the group where s.student_sid is not null:
select
a.name,
sum(case when s.student_sid is null then 0 else 1 end) as student_count
from account a
join inst i on a.inst_sid = i.root_inst_sid
join inst_year iy on i.inst_sid = iy.inst_sid
left join student s
on iy.inst_year_sid = s.inst_year_sid
and s.demo = 0
and s.state = 1
where i.state = 1
and iy.year_sid = 16
and a.account_sid in (20187987, 20188576, 20188755, 52317128, 20189249)
group by a.name;
This is assuming that all of the fields in the student table that you are filtering on are optional. If you don't want to enforce removal of records where, say, s.state does not equal 1, then you need to move the s.state=1 predicate into the WHERE clauses.
If, for some reason, you are getting duplicate student IDs and students are being counted twice, then you can change the aggregate function to this:
count(distinct s.student_id) as student_count
...which is safe to do as count(distinct ...) ignores null values.

SQL Joining tables but getting skipped values

Hi i have joined to tables the code is below. Notice I have used A.Manad = B.Manad which joins data where the month of table A and B is equal. But sometimes table B dont have any data for that month. My code just skip the data, i would rather it just leave it empty or with a value of 0.
The Code takes a list of Orgnr which is swedish for company numbers and joins two tables where the orgnr is the same and the month is the same, but for some reason it doesnt join the data when the value is empty for one company. I still want the orgnr to show up in the joint table.
select Tillnr = A.tillnr, Orgnr = A.orgnr, Månad = A.Manad, Intrastat =
A.varde,Moms = B.vardeutf
into #Tabell1
From
IntrastatFsum A
left outer join
Momsuppg B
on A.Orgnr = B.Orgnr
where A.Orgnr in(
165563137933,165020456017,.......)
AND A.Ar = 2017
AND B.Ar = A.AR
AND A.Manad = 9
AND A.Manad = B.Manad
AND A.InfUtf = 'U'
You should move your WHERE clause AND A.Manad = B.Manad and AND B.Ar = A.AR to the LEFT JOIN clause.
In this way you will preserve all data from table IntrastatFsum:
select Tillnr = A.tillnr, Orgnr = A.orgnr, Månad = A.Manad, Intrastat =
A.varde,Moms = B.vardeutf
into #Tabell1
From
IntrastatFsum A
left outer join
Momsuppg B
on A.Orgnr = B.Orgnr
AND A.Manad = B.Manad
AND A.AR = B.Ar
where A.Orgnr in(
165563137933,165020456017,.......)
AND A.Ar = 2017
AND A.Manad = 9
AND A.InfUtf = 'U'