Trying to extract data from multiple SQL tables. I have a main table and a couple of sub-tables. I want to get all the rows from the main table given a condition and add some fields from the sub-tables. I figured an OUTER JOIN should have worked but I am not getting the entire data.
When I run a COUNT on the main table with the condition I get ~10k rows which is what I am expecting to get once I join the other tables. I understand that I will get NULL values on some row entries.
This is the query I came up with but I am only getting partial results
SELECT main_table.group_id, main_table.floor, sub_table1.Name, sub_table2.base
FROM main_table
LEFT JOIN ON main_table.group_id =sub_table1.group_id
LEFT JOIN ON main_table.group_id =sub_table2.group_id
WHERE main_table.year = 2000 AND sub_table1.year = 2000
AND sub_table2.year = 2000 AND main_table.group = 'C'
I am expecting to see a collection of about 10k rows since that is the number I get when only querying the main table with where clause.
SELECT COUNT(*) FROM main_table WHERE year = 2000 AND group = 'C';
Your where clause is filtering out the extra rows from the outer joins -- effectively turning them into inner joins.
Conditions on all but the first table should be in the on clauses. But I would phrase this as:
SELECT main_table.group_id, main_table.floor, sub_table1.Name, sub_table2.base
FROM main_table LEFT JOIN
sub_table1
ON main_table.group_id = sub_table1.group_id AND
main_table.year = sub_table1.year LEFT JOIN
sub_table2
ON main_table.group_id = sub_table2.group_id AND
main_table.year = sub_table2.year
WHERE main_table.year = 2000 AND main_table.group = 'C';
You want the years to be equal, so that should really be a JOIN condition. Then you only need to specify the year once in the WHERE clause.
Whatever condition in ON clause is used for join and condition in WHERE clause are used to filter out final result.
Apart from gordon's answer, If your requirement is to include different/same years in joins then you can use following query:
SELECT main_table.group_id, main_table.floor, sub_table1.Name, sub_table2.base
FROM main_table LEFT JOIN
sub_table1
ON (main_table.group_id = sub_table1.group_id AND
sub_table1.year = 2000) LEFT JOIN
sub_table2
ON (main_table.group_id = sub_table2.group_id AND
sub_table2.year = 2000)
WHERE main_table.year = 2000 AND main_table.group = 'C';
Cheers!!
Related
SELECT organizations_organization.code as organization,
core_user.email as Created_By,
assinees.email as Assigned_To,
from tickets_ticket
JOIN organizations_organization on tickets_ticket.organization_id = organizations_organization.id
JOIN core_user on tickets_ticket.created_by_id = core_user.id
Left JOIN core_user as assinees on assinees.id = tickets_ticket.currently_assigned_to_id
In the above query, if tickets_ticket.currently_assigned_to_id is null then that that row from tickets_ticket is not returned
> Records In tickets_ticket = 109
> Returned Records = 4 (out of 109 4 row has value for currently_assigned_to_id rest 105 are null )
> Expected Records = 109 (with nulll set for Assigned_To)
Note I am trying to achieve multiple joins on the same table
LEFT JOIN can not kill output records,
your problem is here:
JOIN core_user on tickets_ticket.created_by_id = core_user.id
this join kills non-matching records
try
LEFT JOIN core_user on tickets_ticket.created_by_id = core_user.id
First, this is not the actual code you are running. There is a comma before the from clause that would cause a syntax error. If you have left out a where clause, then that would explain why you are seeing no rows.
When using left joins, conditions on the first table go in the where clause. Conditions on subsequent tables go in the on clause.
That said, a where clause may not be the problem. I would suggest using left joins from the first table onward -- along with table aliases:
select oo.code as organization, cu.email as Created_By, a.email as Assigned_To,
from tickets_ticket tt left join
organizations_organization oo
on tt.organization_id = oo.id left join
core_user cu
on tt.created_by_id = cu.id left join
core_user a
on a.id = tt.currently_assigned_to_id ;
I suspect that you have data in your data model that is unexpected -- perhaps bad organizations, perhaps bad created_by_id. Keep all the tickets to see what is missing.
That said, you should probably be including something like tt.id in the result set to identify the specific ticket.
I have two tables. One table has floor number(tb_FloorNumber.FloorNumber. records :For example 1 to 15) and another table which has Floor number and User_Id column(tb_Emp_Master.FloorNumber, tb_Emp_Master.User_Id). I want to bring all the records from tb_FloorNumber and only the records from tb_Emp_Master with the condition (User_Id = "fat35108").
I know I can do this with two queries like this :
Query 1:
SELECT DISTINCT tb_Emp_Master.FloorNumber
FROM tb_Emp_Master
WHERE (((tb_Emp_Master.User_Id)="fat35108"));
Query2:
SELECT DISTINCT tb_FloorNumber.FloorNumber, Query1.FloorNumber
FROM tb_FloorNumber LEFT JOIN Query1 ON tb_FloorNumber.FloorNumber = Query1.FloorNumber;
But I want to write this query with sing query instead of using Query1 inside the Query 2
I have tried like this:
SELECT DISTINCT tb_FloorNumber.FloorNumber, tb_Emp_Master.FloorNumber
FROM tb_FloorNumber LEFT JOIN tb_Emp_Master ON tb_FloorNumber.FloorNumber = tb_Emp_Master.FloorNumber
WHERE (((tb_Emp_Master.User_Id)="fat35108"));
But it brings only one record (For instance 8)
Please help me how to write this
If you set the condition:
tb_Emp_Master.User_Id = "fat35108"
in the WHERE clause, then you actually get an INNER JOIN instead of a LEFT JOIN because you filter only the matched rows from tb_Emp_Master.
Use tb_Emp_Master in the LEFT JOIN instead of Query1 and set the condition in the ON clause:
SELECT DISTINCT
tb_FloorNumber.FloorNumber,
tb_Emp_Master.FloorNumber
FROM tb_FloorNumber LEFT JOIN tb_Emp_Master
ON tb_FloorNumber.FloorNumber = tb_Emp_Master.FloorNumber AND tb_Emp_Master.User_Id = "fat35108";
I don't know why you need DISTINCT so I use it too.
Below you'll see a simple JOIN statement of 5 base tables, I'm trying to excluded the two LEFT OUTER JOIN statements tables (dandm_emi_cae_statement_links, geod_us_cae_statement_links) from the SQL statement if the column geod_exclude_us_y in the JMD_UDG_DISTRIBUTION table is equal 'N'.
Currently the below statement in the SQL PLAN still looks at these tables, how do I stop it from doing the LEFT OUTER JOIN' if the table JMD_UDG_DISTRIBUTION column geod_exclude_us_y = 'N'?
SELECT lfu.*
FROM JMD_UDG_DISTRIBUTION jud
JOIN dm_lifeline_file_usages lfu
ON lfu.group_id = jud.GROUP_SURR_ID
JOIN dm_lifeline_file_ips lfi
ON lfi.usage_group_id = lfu.group_id
AND lfi.lfu_surr_id = lfu.surr_id
LEFT OUTER JOIN dandm_emi_cae_statement_links dnm
ON jud.geod_exclude_us_y = 'Y'
AND dnm.cae=lfi.cae_number
LEFT OUTER JOIN geod_us_cae_statement_links gucs
ON jud.geod_exclude_us_y = 'Y'
AND gucs.cae_number=lfi.cae_number
Of course. The rules for LEFT JOIN are:
All the rows that match the ON condition.
All rows in the first table when there is no match in the second.
So, a condition on the first table in ON has no impact on the results. That is not strictly true. There is a weird sort of impact. The columns from the second table -- even for otherwise matching rows -- are NULL.
So, you want to filter in the WHERE clause. Move jud.geod_exclude_us_y = 'Y' from the ON clauses to:
WHERE jud.geod_exclude_us_y = 'Y'
Why, in this query, is the final 'WHERE' clause needed to limit duplicates?
The first LEFT JOIN is linking programs to entities on a UID
The first INNER JOIN is linking programs to a subquery that gets statistics for those programs, by linking on a UID
The subquery (that gets the StatsForDistributorClubs subset) is doing a grouping on UID columns
So, I would've thought that this would all be joining unique records anyway so we shouldn't get row duplicates
So why the need to limit based on the final WHERE by ensuring the 'program' is linked to the 'entity'?
(irrelevant parts of query omitted for clarity)
SELECT LmiEntity.[DisplayName]
,StatsForDistributorClubs.*
FROM [Program]
LEFT JOIN
LMIEntityProgram
ON LMIEntityProgram.ProgramUid = Program.ProgramUid
INNER JOIN
(
SELECT e.LmiEntityUid,
sp.ProgramUid,
SUM(attendeecount) [Total attendance],
FROM LMIEntity e,
Timetable t,
TimetableOccurrence [to],
ScheduledProgramOccurrence spo,
ScheduledProgram sp
WHERE
t.LicenseeUid = e.lmientityUid
AND [to].TimetableOccurrenceUid = spo.TimetableOccurrenceUid
AND sp.ScheduledProgramUid = spo.ScheduledProgramUid
GROUP BY e.lmientityUid, sp.ProgramUid
) AS StatsForDistributorClubs
ON Program.ProgramUid = StatsForDistributorClubs.ProgramUid
INNER JOIN LmiEntity
ON LmiEntity.LmiEntityUid = StatsForDistributorClubs.LmiEntityUid
LEFT OUTER JOIN Region
ON Region.RegionId = LMIEntity.RegionId
WHERE (
[Program].LicenseeUid = LmiEntity.LmiEntityUid
OR
[LMIEntityProgram].LMIEntityUid = LmiEntity.LmiEntityUid
)
If you were grouping in your outer query, the extra criteria probably wouldn't be needed, but only your inner query is grouped. Your LEFT JOIN to a grouped inner query can still result in multiple records being returned, for that matter any of your JOINs could be the culprit.
Without seeing sample of duplication it's hard to know where the duplicates originate from, but GROUPING on the outer query would definitely remove full duplicates, or revised JOIN criteria could take care of it.
You have in result set:
SELECT LmiEntity.[DisplayName]
,StatsForDistributorClubs.*
I suppose that you dublicates comes from LMIEntityProgram.
My conjecture: LMIEntityProgram - is a bridge table with both LmiEntityId an ProgramId, but you join only by ProgramId.
If you have several LmiEntityId for single ProgramId - you must have dublicates.
And this dublicates you're filtering in WHERE:
[LMIEntityProgram].LMIEntityUid = LmiEntity.LmiEntityUid
You can do it in JOIN:
LEFT JOIN LMIEntityProgram
ON LMIEntityProgram.ProgramUid = Program.ProgramUid
AND [LMIEntityProgram].LMIEntityUid = LmiEntity.LmiEntityUid
I have the following query:
SELECT MS.idReg, MS.dsMotivo, A.contrato FROM MS
INNER JOIN S
ON S.motivoSiniestro = MS.idReg
INNER JOIN C
ON C.n__contrat = S.n__contrat
INNER JOIN A
ON A.n__article = C.n__article
Table MS has only 12 records, the ones I need and others have many more entries.
My problem is that I only want the 12 records from MS and their contrato column but I'm getting much more that that. Have tried many combinations of INNER, OUTER, LEFT and RIGHT joins. Any help?
You get too many records because there are several A.contrato values for each row in the MS table. Sql server does not know which one of all the A.contrato values to take so it returns all of them. First you need to decide which one you want.
If any will do you can simply write your query like this:
SELECT MS.idReg, MS.dsMotivo, MAX(A.contrato)
FROM MS
INNER JOIN S
ON S.motivoSiniestro = MS.idReg
INNER JOIN C
ON C.n__contrat = S.n__contrat
INNER JOIN A
ON A.n__article = C.n__article
GROUP BY MS.idReg, MS.dsMotivo
Try this one -
SELECT MS.idReg, MS.dsMotivo, A.contrato
FROM dbo.MS
OUTER APPLY (
SELECT TOP 1 A.contrato
FROM dbo.S
JOIN dbo.C ON C.n__contrat = S.n__contrat
JOIN dbo.A ON A.n__article = C.n__article
WHERE S.motivoSiniestro = MS.idReg
) s