select left join table use and condition - sql

these two query output different result,
I have question AND m.status = $1 ...each condition follow the left join table or move to the final part, thats different ??
query 1
SELECT count(mua.*)
AS total_row_count
FROM media_user_action mua
LEFT JOIN media m ON m.id = mua.media_id
AND m.status = $1
LEFT JOIN gallery_media gm ON gm.id = mua.media_id
LEFT JOIN gallery g ON g.id = gm.gallery_id
AND g.status = $1
LEFT JOIN "user" mcbu ON mcbu.id = m.create_by_user_id
AND mcbu.status = $1
LEFT JOIN "user" gcbu ON gcbu.id = g.create_by_user_id
AND gcbu.status = $1
WHERE mua.user_id = $2
query 2
SELECT count(mua.*)
AS total_row_count
FROM media_user_action mua
LEFT JOIN media m ON m.id = mua.media_id
LEFT JOIN gallery_media gm ON gm.id = mua.media_id
LEFT JOIN gallery g ON g.id = gm.gallery_id
LEFT JOIN "user" mcbu ON mcbu.id = m.create_by_user_id
LEFT JOIN "user" gcbu ON gcbu.id = g.create_by_user_id
WHERE
m.status = $1
AND g.status = $1
AND mcbu.status = $1
AND gcbu.status = $1
AND mua.user_id = $2
UPDATE
base on below answer
if I want make sure return result, must all related/left join table status both equal $1, ( join table recode could be null) so I have to add AND x.status .. follow the join table, right?

When you use left outer join, value of the right table may be NULL.
For simplicity's sake, let say we have
Table A (id, name) and Table B (fid, status)
Then query1 will be like
select A.id, B.status
from A
left join (select * from B where status = $1)
on A.id = B.fid;
so result could have B.status is NULL
And query2 will be like
select C.*
from (select A.id, B.status
from A
left join B
on A.id = B.fid
) C
where C.status = $1;
It's equal to
select *
from A
inner join B
on A.id = B.fid
where B.status = $1;
So B.status must exactly be $1, and is never NULL

When you put WHERE conditions on tables that you have LEFT JOIN-ed, and that require some their fields to have non-NULL values, then you are actually converting the LEFT JOIN into an INNER JOIN.
This is because a LEFT JOIN may produce results where the joined table has no matching record. In that case all fields of that "virtual" record have value NULL. So by requiring that one of those fields is not null, you remove those instances from the result.
If on the contrary, you put such conditions in the LEFT JOIN condition, then you do not break this mechanism, where the a non-match will still give a result, albeit with NULL.

An outer join means that additionally to an inner join, when no match is found a mock record with all columns null gets joined.
So let's say for one mua we don't find a matching m. Then we get an m record with all columns null. m.status is null. With WHERE m.status = $1 you dismiss that record, however, so you are where you were with a simple inner join.
Criteria on outer-joined tables belongs in the ON clause.

Related

Full outer join a table to another table that's being left joined to the main table

So i've got hte below code that works for the most part but when I'm trying to bring in the last table i cant get the expected results.
SELECT
CASE
WHEN CCO.Account_Manager__c IS NULL THEN Opp.OwnerId ELSE CCO.Account_Manager__c
END AS AccountManager,
CCO.Account_Associate__c as ClientOfficeAccountAssociate,
Opp.OwnerId as AccountOwnerId,
CCO.Account_Manager__c as ClientOfficeAM,
ACC.Name as AccountName,
OPP.Forum_Monthly_Recurring_Revenue_MRR__c,
PAYG.Revenue
LEFT JOIN `round-cacao-234512.salesforce.Opportunity` as OPP
ON OPP.Id = Split.OpportunityId AND OPP.OwnerId = Split.SplitOwnerId
LEFT JOIN `round-cacao-234512.salesforce.Account` as ACC
on ACC.Id = OPP.AccountId
LEFT JOIN `round-cacao-234512.salesforce.User` as USER
ON USER.Id = OPP.OwnerId
LEFT JOIN `round-cacao-234512.salesforce_df.Company_Client_Office__c` as CCO
ON CCO.Opportunity__c = OPP.Id
LEFT JOIN `round-cacao-234512.salesforce.Client_Office_Intranet__c` as COI
ON COI.Id = CCO.Client_Office_Intranet__c
LEFT JOIN `round-cacao-234512.salesforce.RecordType` as RT
ON RT.Id = OPP.RecordTypeId
LEFT JOIN `commercial-analysis.materialised.2022AMDashForumRRQuotas` as Quota
on Quota.AccountID = CCO.Account_Manager__c OR Quota.AccountID = Opp.OwnerId
LEFT JOIN `commercial-analysis.2022_AM_Territory.FPAYG_Quotas` as PAYGQuota
on PAYGQuota.ClientOffice = COI.Name
Full Outer JOIN `round-cacao-234512.materialised.2022AMDashPAYGRevenue` PAYGRev
on PAYGRev.ClientOffice = COI.Name
So my last table round-cacao-234512.materialised.2022AMDashPAYGRevenue will be joined on clientoffice but will also have client offices that don't appear in COI, so I want those to come in with nulls on all the values that don't match up.
Hope that makes sense

inner join on multiple conditions when using a database link

Could someone help me figure out why my inner join won't work when I try to use multiple conditions? I'm using a database link to connect my tables, and then using "and" for my second condition. When I only have the first inner join on a.E_id = b.eid it shows results but when I add the second condition it turns up blank...
my code:
select count(*)
from table1#dblink a
inner join table2 b
on a.E_id = b.eid
and a.BUS_ID = b.B_NUMBER
where b.pricing_system = 'M'
;
I have used wildcard character % with like operator. Try below query:
select count(*)
from table1#dblink a
inner join table2 b
on a.E_id = b.eid
and a.BUS_ID like '%'||b.B_NUMBER||'%'
where b.pricing_system = 'M';
If the inner join can't find records with the condition the result will be no rows.
If you want the rows even if the second condition doesn't match, then change it for Left join and change the condition for a Like
And if the 'M' character is in diferents positions of the field, then use the character '%'
You should use this:
select count(*)
from table1#dblink a
Left join table2 b
on a.E_id = b.eid
and a.BUS_ID = b.B_NUMBER
and b.pricing_system = '%M%';

Problem with where clause and count transactions?

I want to count how many transactions I have by Currency. When I count without a where clause I get 0 transactions where I have NULL values but when I use a where clause with an IN operator I get a filtered result and no zero results. How to show 0 in count transactions?
SELECT
c.ShortName,
count(ad.AccountId) as No_of_transactions
FROM Currency c
LEFT JOIN Account a ON c.id = a.CurrencyId
LEFT JOIN AccountDetails ad ON a.id = ad.AccountId
LEFT JOIN [Location] l ON ad.LocationId = l.Id
LEFT JOIN LocationType lt ON l.LocationTypeId = lt.Id
WHERE lt.Name IN('Region Branch', 'City Branch')
GROUP BY c.ShortName
This is the result that I want to get:
EUR 31,
USD 0,
GBR 0
You have a LEFT JOIN. The filtering needs to go in the ON clause:
SELECT c.ShortName,
COUNT(lt.id) as No_of_transactions
FROM Currency c LEFT JOIN
Account a
ON c.id = a.CurrencyId LEFT JOIN
AccountDetails ad
ON a.id = ad.AccountId LEFT JOIN
[Location] l
ON ad.LocationId = l.Id LEFT JOIN
LocationType lt
ON l.LocationTypeId = lt.Id AND
lt.Name IN ('Region Branch', 'City Branch')
GROUP BY c.ShortName;
In your version, the non-matches turn into NULLs, which the WHERE conditions filter out.
You want to move the condition on the left joined table from the where clause to the on clause of the relevant join to avoid records being filtered out when they do not exist in that table.
Also, I think that you need COUNT(DISTINCT ad.id) (as per the comments, a transaction is uniquely represented by this column):
SELECT
c.ShortName,
COUNT(DISTINCT ad.id) as No_of_transactions
FROM Currency c
LEFT JOIN Account a ON c.id = a.CurrencyId
LEFT JOIN AccountDetails ad ON a.id = ad.AccountId
LEFT JOIN [Location] l ON ad.LocationId = l.Id
LEFT JOIN LocationType lt ON l.LocationTypeId = lt.Id AND lt.Name IN('Region Branch', 'City Branch')
GROUP BY c.ShortName
SELECT
c.ShortName,
COUNT(t.Id) as No_of_transations
FROM Currency c
LEFT JOIN Account a ON c.id = a.CurrencyId
LEFT JOIN AccountDetails ad ON a.id = ad.AccountId
LEFT JOIN [Location] l ON ad.LocationId = l.Id
LEFT JOIN (SELECT * FROM LocationType lt WHERE lt.Name IN('Region Branch', 'City
Branch')) AS t ON l.LocationTypeId = t.Id
GROUP BY c.ShortName

Trouble with aggregate in Where clause, Selecting Max(x) When Max(x) != 3

I am trying to reconfigure the below sql to only pull records when the Max(Field) != 3 but keep getting an error (detailed) below.
This is the code before adding the Where Max(field) != 3
SELECT P.Code,
MAX(PW.v1) AS V1
FROM SW
INNER JOIN S ON SW.S_Id = S.Id
INNER JOIN PW ON SW.PW_Id = PW.Id
INNER JOIN PON S.P_Id = P.id
WHERE S.P_Id = P.id
GROUP BY P.Code
My Attempt
SELECT P.Code,
MAX(PW.v1) AS V1
FROM SW
INNER JOIN S ON SW.S_Id = S.Id
INNER JOIN PW ON SW.PW_Id = PW.Id
INNER JOIN PON S.P_Id = P.id
WHERE S.P_Id = P.id
AND (SELECT MAX(PW.v1)
FROM SW AS SW2
WHERE SW.PWId = SW2.PW_Id) != 3
GROUP BY P.Code
This is the error I get and not sure what to do:
An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.
Traditional method of filtering on results of an aggregate can be achieved by using HAVING clause. I also removed the unnecessary WHERE clause as you already joined those 2 tables on that column. Here is the query:
SELECT P.Code
,MAX(PW.v1) AS V1
FROM SW
INNER JOIN S
ON SW.S_Id = S.Id
INNER JOIN PW
ON SW.PW_Id = PW.Id
INNER JOIN P
ON S.P_Id = P.id
GROUP BY P.Code
HAVING MAX(PW.v1)!=3;

SQL - Join issue

I have the following query:
SELECT rt.ID, rt.Name, rt.Rate, rt.Colour, vtb.ID AS 'vtbID', vtb.Value, rt.StdID
FROM Rates AS rt
LEFT OUTER JOIN VehicleTypeCostsBreakdown AS vtb ON rt.ID = vtb.RateID
LEFT OUTER JOIN VehicleTypeCostsDepots AS vtd ON vtd.ID = vtb.VehicleTypeDepotID AND vtd.DepotID = #DepotID AND vtd.VehicleTypeID = #VehicleTypeID
Basically, I want to select all 'rates' from Rates table, but if any references to a rate exists in the 'vtd' table, which has parameters that match #DepotID and #VehicleTypeID, I want to bring back the Value for that. If it doesn't have any referenced, I want it the 'vtb.Value' selection to be blank.
With the SQL above, it seems to always return a value for 'vtb.Value' value, even if the parameters are null. Am I missing something?
Try it this way. Basically, you'll LEFT JOIN to the derived table formed by the INNER JOIN between VehicleTypeCostsBreakdown and VehicleTypeCostsDepots. The INNER JOIN will only match when all of your conditions are true.
SELECT rt.ID, rt.Name, rt.Rate, rt.Colour, vtb.ID AS 'vtbID', vtb.Value, rt.StdID
FROM Rates AS rt
LEFT OUTER JOIN VehicleTypeCostsBreakdown AS vtb
INNER JOIN VehicleTypeCostsDepots AS vtd
ON vtd.ID = vtb.VehicleTypeDepotID
AND vtd.DepotID = #DepotID
AND vtd.VehicleTypeID = #VehicleTypeID
ON rt.ID = vtb.RateID
Try:
SELECT rt.ID, rt.Name, rt.Rate, rt.Colour, vtb.ID AS 'vtbID', vtb.Value, rt.StdID
FROM Rates AS rt
LEFT OUTER JOIN (SELECT b.ID, b.Value, b.RateID
FROM VehicleTypeCostsBreakdown AS b
JOIN VehicleTypeCostsDepots AS d
ON d.ID = b.VehicleTypeDepotID AND
d.DepotID = #DepotID AND
d.VehicleTypeID = #VehicleTypeID)
AS vtb ON rt.ID = vtb.RateID
Try this:
SELECT rt.ID, rt.Name, rt.Rate, rt.Colour, vtb.ID AS 'vtbID', vtb.Value, rt.StdID
FROM Rates AS rt
LEFT JOIN VehicleTypeCostsBreakdown AS vtb ON rt.ID = vtb.RateID
LEFT JOIN VehicleTypeCostsDepots AS vtd ON vtd.ID = vtb.VehicleTypeDepotID
WHERE vtd.ID IS NULL OR (vtd.DepotID = #DepotID AND vtd.VehicleTypeID = #VehicleTypeID)
You don't need to specify that the LEFT JOIN is an OUTER JOIN and you shouldn't put conditions in the ON section of a JOIN, that's what WHERE is for.