Multiple left joins in a single statement - sql

I have multiple queries that I'm trying to combine into a single one with no luck. I'm using left join on the same table twice with a different field and that sounds wrong.
SELECT a.*
, b.CODE_DESCRIPTION AS highest_grade
FROM BBOP.EP_MAIN_FACT a
LEFT JOIN BBOP.EP_CODE_WORK b
ON a.HIGHESTGRADE_CA = b.code
AND code_type LIKE 'High%'
LEFT JOIN BBOP.EP_CODE_WORK ab
ON a.Goal_Steps = ab.code
AND code_type LIKE 'Goal%'
WHERE plan_date BETWEEN '01-mar-2019' AND '31-may-2019';
-- ORA-00918: column ambiguously defined
00918. 00000 - "column ambiguously defined"
Here are the 2 queries, separately they produce results with no problems.
-- Highest Grade
SELECT a.*
, b.CODE_DESCRIPTION AS highest_grade_desc
FROM BBOP.EP_MAIN_FACT a
LEFT JOIN BBOP.EP_CODE_WORK b
ON a.HIGHESTGRADE_CA = b.code
WHERE plan_date BETWEEN '01-mar-2019' AND '31-may-2019'
AND code_type LIKE 'High%';
-- Goals
SELECT a.*
, b.CODE_DESCRIPTION AS Goal
FROM BBOP.EP_MAIN_FACT a
LEFT JOIN BBOP.EP_CODE_WORK b
ON a.Goal_Steps = b.code
WHERE plan_date BETWEEN '01-mar-2019' AND '31-may-2019'
AND code_type LIKE 'Goal%';

I think you want:
select mf.*, coalesce(cwh.CODE_DESCRIPTION, cwg.CODE_DESCRIPTION) as highest_grade
from BBOP.EP_MAIN_FACT mf left join
BBOP.EP_CODE_WORK cwh
on mf.HIGHESTGRADE_CA = cwh.code and
cwh.code_type like 'High%' left join
BBOP.EP_CODE_WORK cwg
on mf.Goal_Steps = cwg.code and
cwg.code_type like 'Goal%'
where mf.plan_date >= date '2019-03-01' and
mf.plan_date < date '2019-06-01';
Notes:
In a query that references multiple tables, qualify all column references. This is the root of your problem. You have "bare" column references in the on clauses.
Use meaningful table aliases, rather than arbitrary letters.
The coalesce() chooses the values based on the priority order of the joins.
Oracle supports the date keyword to introduce date literals. This is safer than relying on default formats which may change on a given server.
between is dangerous for dates, particularly in Oracle where the date type always has a time component. Inequalities capture the logic.

As someone has already stated in comments, the columns plan_date and code_type need to have table alias specified in their usage.
I am guessing at least one of these columns is in BBOP.EP_CODE_WORK table and hence the table alias needs to be specified while referencing these colums.
Regards
Akash

Related

SQL Inner Join using selections instead of table names

I have two tables that I'm trying to perform an Inner join on tables tab1 and tab2 have different lengths but have common data in tab1_col2 and tab2_col2 (alias_2/alias_4)
select
tab1_col1 as alias_1,
tab1_col2 as alias_2,
from db.schema.tab1
inner join (
select
tab2_col1 as alias_3,
tab2_col2 as alias_4,
tab2_colx as alias_x
from db.schema.tab2
) on db.schema.tab1.alias_2 = db.schema.tab2.alias_4
I keep on getting the error there is an entry for "tab2" but it can't be referenced in this part of the query.
Don't use 3 part naming its not best practice.
You can't reference a column alias in the same scope its declared (except for in the order by clause) so you can't access alias_2 in your join condition. You have to use the actual column name.
You can't access table names within a sub-query/derived-table from outside that context, so you must alias it and use that alias.
Best practice is give all you tables/derived-tables short but meaningful aliases - it makes the query much clearer.
select
tab1_col1 as alias_1,
tab1_col2 as alias_2,
from [schema].tab1 as T1
inner join (
select
tab2_col1 as alias_3,
tab2_col2 as alias_4,
tab2_colx as alias_x
from [schema].tab2
) as T2 on T2.alias_4 = T1.tab1_col2;

The Inner join in my sql code is not working and how do i select only particular colums from the second table?

SELECT "KNDNR","HZDAT"
FROM "INFM_RBINPJDT_CSC1"."V_REPL_CE10010_C3" AS A
WHERE SUBSTR("HZDAT",1,4) = EXTRACT(YEAR FROM SYSDATE)
INNER JOIN "INFM_RBINPJDT_CSC1"."V_REPL_KNA1_C3" ON
"INFM_RBINPJDT_CSC1"."V_REPL_CE10010_C3"."KNDNR" = "INFM_RBINPJDT_CSC1"."V_REPL_KNA1_C3"."KUNNR"
This is my code. Here until the inner join the code is working. The inner join statement is not working. Its showing error as "Command not ended properly".
I am using this to import tables into Power BI.
And i also want to select only few columns from the 2nd table as well.
schema name:"INFM_RBINPJDT_CSC1"
table1 name:"V_REPL_CE10010_C3"
table2 name:"V_REPL_KNA1_C3"
column name:"KNDNR","KNDNR"
Here's how you should construct your query. Join first before doing any Where conditions.
Then use your table alias to join the columns B.* of your 2nd table
SELECT A."KNDNR",A."HZDAT", B."KNDNR"
FROM "INFM_RBINPJDT_CSC1"."V_REPL_CE10010_C3" AS A
INNER JOIN "INFM_RBINPJDT_CSC1"."V_REPL_KNA1_C3" AS B ON B."KNDNR" = A."KUNNR"
WHERE SUBSTR(A."HZDAT",1,4) = EXTRACT(YEAR FROM SYSDATE)
Try moving your joins before your WHERE clause and using your table alias in the ON condition:
SELECT "KNDNR","HZDAT"
FROM "INFM_RBINPJDT_CSC1"."V_REPL_CE10010_C3" AS A
INNER JOIN "INFM_RBINPJDT_CSC1"."V_REPL_KNA1_C3" AS B ON A."KNDNR" = B."KUNNR"
WHERE SUBSTR("HZDAT",1,4) = EXTRACT(YEAR FROM SYSDATE)
Your query is messed up in multiple ways. Obviously, the clauses are in the incorrect order. You should also:
use meaningful table aliases
eschew comparisons between strings and numbers
qualify the column names
So:
SELECT rc."KNDNR", "HZDAT"
FROM "INFM_RBINPJDT_CSC1"."V_REPL_CE10010_C3" rc INNER JOIN
"INFM_RBINPJDT_CSC1"."V_REPL_KNA1_C3" rk
ON rc."KNDNR" = rk."KUNNR"
WHERE SUBSTR("HZDAT", 1, 4) = TO_CHAR(SYSDATE, 'YYYY');
You should also qualify HZDAT, but I don't know what table/view that comes from.

SQL - Table Join To Compare NULL Values Where Join is NULL

I've been asked to basically write a report that displays data in two different databases and be able to see in either database if something is missing.
IE, the invoice number may exist in database1, but not in database2 and vice versa.
I've got the following query below but it only returns all the data from the second table, with NULL values for the first. I'd like to set it up to return the NULL Values in both, but I think the problem is because my join is on the values that can be NULL, so it won't return the values that exist in the first table and not the second.
Can someone step me through how to resolve an issue like this?
As far as I'm aware, I don't necessarily have any other tables to join unless I try to join more tables from each database.
Query:
Select TC.PO_Number, TC.Invoice_Date, TC.Invoice_, H.RefPoNum, H.InvoiceNum
From Table1 TC
RIGHT JOIN [SERVERNAME].[DBNAME].[TABLE2] H ON (TC.Invoice_ = H.InvoiceNum)
Where TC.Invoice_Date Between '2018-10-31' AND '2018-10-31'
AND H.Company Like 'COMPANY'
You can do what you want with a full join. Filtering is tricky with a full join, so I recommend subqueries:
select tc.PO_Number, tc.Invoice_Date, tc.Invoice_, h.RefPoNum, h.InvoiceNum
From (select tc.*
from Table1 tc
where tc.Invoice_Date Between '2018-10-31' AND '2018-10-31'
) tc full join
(select h.*
from [SERVERNAME].[DBNAME].[TABLE2] h
where h.Company Like 'COMPANY'
) h
on TC.Invoice_ = H.InvoiceNum;
Just make sure that the column you are comparing has the same data type and you can safely use this query below:
Server01 NOT IN Server02
select t1.InvoiceNumber from server01.dbo.Invoice t1
except
select t2.InvoiceNumber from server02.dbo.Invoice t2
Server02 NOT IN Server01
select t1.InvoiceNumber from server02.dbo.Invoice t1
except
select t2.InvoiceNumber from server01.dbo.Invoice t2
P.S.
While this may not be the exact query you are looking for, but this template may help.

How to find the most frequent value in a select statement as a subquery?

I am trying to get the most frequent Zip_Code for the Location ID from table B. Table A(transaction) has one A.zip_code per Transaction but table B(Location) has multiple Zip_code for one area or City. I am trying to get the most frequent B.Zip_Code for the Account using Location_D that is present in both table.I have simplified my code and changed the names of the columns for easy understanding but this is the logic for my query I have so far.Any help would be appreciated. Thanks in advance.
Select
A.Account_Number,
A.Utility_Type,
A.Sum(usage),
A.Sum(Cost),
A.Zip_Code,
( select B.zip_Code from B where A.Location_ID= B.Location_ID having count(*)= max(count(B.Zip_Code)) as Location_Zip_Code,
A.Transaction_Date
From
Transaction_Table as A Left Join
Location Table as B On A.Location_ID= B.Location_ID
Group By
A.Account_Number,
A.Utility_Type,
A.Zip_Code,
A.Transaction_Date
This is what I come up with:
Select tt.Account_Number, tt.Utility_Type, Sum(tt.usage), Sum(tt.Cost),
tt.Zip_Code,
(select TOP 1 l.zip_Code
Location_Table l
where tt.Location_ID = l.Location_ID
group by l.zip_code
order by count(*) desc
) as Location_Zip_Code,
tt.Transaction_Date
From Transaction_Table tt
Group By tt.Account_Number, tt.Utility_Type, tt.Zip_Code, tt.Transaction_Date;
Notes:
Table aliases are a good thing. However, they should be abbreviations for the tables referenced, rather than arbitrary letters.
The table alias qualifies the column name, not the function. Hence sum(tt.usage) rather than tt.sum(usage).
There is no need for a join in the outer query. You are doing all the work in the subquery.
An order by with top seems the way to go to get the most common zip code (which, incidentally, is called the mode in statistics).

Need help understanding a complex query with multiple join conditions

I have a query that I am trying to understand. Can someone shed light on to the details of what this query does?
I've only ever used one ON clause in a join condition. This one has multiple conditions for the LEFT JOIN, making it tricky to understand.
INSERT INTO nop_tbl
(q_date, community_id, newsletter_t, subscription_count)
SELECT date(now()), a.community_id,
a.newsletter_type,
count(a.subscriber_user_id)
FROM
newsletter_subscribers_main a
LEFT OUTER JOIN nop_tbl b
ON (a.community_id = b.community_id)
AND (a.newsletter_type = b.newsletter_t)
AND (a.created_at = b.q_date)
WHERE b.q_date is null
AND b.mailing_list is null
GROUP BY a.community_id, a.newsletter_t, a.created_at
You have your explanation:
The objective of the query is to count subscriptions per (q_date, community_id, newsletter_t) in newsletter_subscribers_main and write the result to nop_tbl.
The LEFT JOIN prevents that rows are added multiple times.
But I also think, the query is inefficient and probably wrong.
The 2nd WHERE clause:
AND b.mailing_list is null
is just noise and can be removed. If b.q_date is null, then b.mailing_list is guaranteed to be null in this query.
You don't need parentheses around JOIN conditions.
If subscriber_user_id is defined NOT NULL, count(*) does the same, cheaper.
I suspect that grouping by a.created_at, while you insert date(now()) is probably wrong. Hardly makes any sense. My educated guess (assuming that created_at is type date):
INSERT INTO nop_tbl
(q_date, community_id, newsletter_t, subscription_count)
SELECT a.created_at
,a.community_id
,a.newsletter_type
,count(*)
FROM newsletter_subscribers_main a
LEFT JOIN nop_tbl b ON a.community_id = b.community_id
AND a.newsletter_type = b.newsletter_t
AND a.created_at = b.q_date
WHERE b.q_date IS NULL
GROUP BY a.created_at, a.community_id, a.newsletter_t;
The short short version is:
insert ... select ...
-> the query is filling nob_tbl
from ...
-> based on data in newsletter_subscribers_main
left join ... where ... is null
-> that are not already present in nob_tbl
Step by step
INSERT INTO nop_tbl
(q_date, community_id, newsletter_t, subscription_count)
The INSERT syntax This is telling the database in what table and what column will be used for the insert query
SELECT date(now()), a.community_id,
a.newsletter_type,
count(a.subscriber_user_id)
Those are instead the selected fields to insert
FROM
newsletter_subscribers_main a
Here is telling to the database to select fields which has alias prepended a. from table newsletter_subscribers_main
LEFT OUTER JOIN nop_tbl b
Here is left joining another table nop_tbl where other fields will be selected
ON (a.community_id = b.community_id)
AND (a.newsletter_type = b.newsletter_t)
AND (a.created_at = b.q_date)
Those are the rules of the JOIN, actually is telling what columns will be used for join
WHERE b.q_date is null
AND b.mailing_list is null
Those are the WHERE clauses , they are used to limit result to the requested data, in this case where two columns are null
GROUP BY a.community_id, a.newsletter_t, a.created_at
GROUP BY clauses, used to group result on given column
You can have a visual explanation of joins here