SQL Inner Join using selections instead of table names - sql

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;

Related

How to perform an INNER JOIN on columns with the same name

I am essentially swapping out the contents of column "LocationId" in the User table with the contents of column "LocationId" in table ChaplainLocation.
I tried a few INNER JOIN statements but have run into issues when it comes to differentiating between the two columns. I also tried setting aliases to no avail.
SELECT a.LocationID FROM [User] AS table1a,
a.ChaplainId,
a.FullName,
b.LocationId FROM [ChaplainLocation] AS table2b,
b.ChaplainId
FROM table1 a
INNER JOIN table2 b
ON a.LocationId = b.LocationId'''
I know the above SQL is messy, but I am new to INNER JOIN. I need the LocationId from table ChaplainLocation to replace LocationId in the User table.
Your current syntax is slightly off. Table aliases belong next to table names, and those appear in the FROM and JOIN clauses.
SELECT
a.LocationID AS LocationID_a,
a.ChaplainId AS ChaplainId_a,
a.FullName,
b.LocationId AS LocationId_b,
b.ChaplainId AS ChaplainId_b
FROM [User] AS a
INNER JOIN [ChaplainLocation] AS b
ON a.LocationId = b.LocationId;
Note that there is nothing wrong with referring to more than one column bearing the same name, so long as you qualify that column reference with a table alias (or full table name) to distinguish it.

Multiple left joins in a single statement

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

join three table in oracle 11g

i have three table to join in select query .. this query not working
select policy_master.POLICY_REFER ,policy_master.CLIENT_NAME ,policy_master.ADRESS ,policy_master.POLICY_CLASS ,policy_master.POLICY_PRODUCT ,policy_master.EXECUTIVE_NAME ,policy_master.COMM_DATE ,
policy_master.EXPIRY_DATE ,policy_master.RENEWAL_DATE ,policy_master.GROSS ,policy_master.FED ,policy_master.FIF ,policy_master.STAMP_DUTY ,policy_master.PERMIUM ,policy_master.DESCRIPTION,
POLICY_INSURER_DETAIL.INSURER_NAME,POLICY_INSURER_DETAIL.POLICY_NUMBER,POLICY_INSURER_DETAIL.P_SHARE,POLICY_INSURER_DETAIL.G_PREMIUM,POLICY_INSURER_DETAIL.BROKER_P,POLICY_INSURER_DETAIL.LEVY,
POLICY_INSURER_DETAIL.LEVY,POLICY_SUBAGENT_DETAIL.SUBAGENT_NAME,POLICY_SUBAGENT_DETAIL.BUSSINES_SHARE,POLICY_SUBAGENT_DETAIL.COMM_P,POLICY_SUBAGENT_DETAIL.COMM_VALUE
from POLICY_MASTER INNER JOIN POLICY_INSURER_DETAIL
on policy_master.policy_refer = POLICY_INSURER_DETAIL.POLICY_REFER and
policy_master.policy_refer = POLICY_SUBAGENT_DETAIL.POLICY_REFER;
Please tell me what i should do
To simplify the answer I've removed all explicit columns and replaced them with select *.
You have only joined two tables. You are refering to policy_subagent_detail table inside a join to policy_insurer_detail (but you're not joining the subagent details table). You should join this table and specify joining conditions in order to be able to retrieve columns from it (as you did in your column list near select keyword).
I've also added table aliases to make your code shorter.
select *
from POLICY_MASTER pm
inner join POLICY_INSURER_DETAIL pid on
pm.policy_refer = pid.POLICY_REFER
inner join POLICY_SUBAGENT_DETAIL psd on -- added join
pm.policy_refer = psd.POLICY_REFER
do inner join of the third table required you missed iton the from clause . thats it .OR you can use where clause like
from table1 a,table2 b,table3 c
where a.colname= b.colname and
b.colname=c.colname.

INNER JOIN vs IN

SELECT C.* FROM StockToCategory STC
INNER JOIN Category C ON STC.CategoryID = C.CategoryID
WHERE STC.StockID = #StockID
VS
SELECT * FROM Category
WHERE CategoryID IN
(SELECT CategoryID FROM StockToCategory WHERE StockID = #StockID)
Which is considered the correct (syntactically) and most performant approach and why?
The syntax in the latter example seems more logical to me but my assumption is the JOIN will be faster.
I have looked at the query plans and havent been able to decipher anything from them.
Query Plan 1
Query Plan 2
The two syntaxes serve different purposes. Using the Join syntax presumes you want something from both the StockToCategory and Category table. If there are multiple entries in the StockToCategory table for each category, the Category table values will be repeated.
Using the IN function presumes that you want only items from the Category whose ID meets some criteria. If a given CategoryId (assuming it is the PK of the Category table) exists multiple times in the StockToCategory table, it will only be returned once.
In your exact example, they will produce the same output however IMO, the later syntax makes your intent (only wanting categories), clearer.
Btw, yet a third syntax which is similar to using the IN function:
Select ...
From Category
Where Exists (
Select 1
From StockToCategory
Where StockToCategory.CategoryId = Category.CategoryId
And StockToCategory.Stock = #StockId
)
Syntactically (semantically too) these are both correct. In terms of performance they are effectively equivalent, in fact I would expect SQL Server to generate the exact same physical plans for these two queries.
T think There are just two ways to specify the same desired result.
for sqlite
table device_group_folders contains 10 records
table device_groups contains ~100000 records
INNER JOIN: 31 ms
WITH RECURSIVE select_childs(uuid) AS (
SELECT uuid FROM device_group_folders WHERE uuid = '000B:653D1D5D:00000003'
UNION ALL
SELECT device_group_folders.uuid FROM device_group_folders INNER JOIN select_childs ON parent = select_childs.uuid
) SELECT device_groups.uuid FROM select_childs INNER JOIN device_groups ON device_groups.parent = select_childs.uuid;
WHERE 31 ms
WITH RECURSIVE select_childs(uuid) AS (
SELECT uuid FROM device_group_folders WHERE uuid = '000B:653D1D5D:00000003'
UNION ALL
SELECT device_group_folders.uuid FROM device_group_folders INNER JOIN select_childs ON parent = select_childs.uuid
) SELECT device_groups.uuid FROM select_childs, device_groups WHERE device_groups.parent = select_childs.uuid;
IN <1 ms
SELECT device_groups.uuid FROM device_groups WHERE device_groups.parent IN (WITH RECURSIVE select_childs(uuid) AS (
SELECT uuid FROM device_group_folders WHERE uuid = '000B:653D1D5D:00000003'
UNION ALL
SELECT device_group_folders.uuid FROM device_group_folders INNER JOIN select_childs ON parent = select_childs.uuid
) SELECT * FROM select_childs);

SQL 2005 - The column was specified multiple times

I am getting the following error when trying to run this query in SQL 2005:
SELECT tb.*
FROM (
SELECT *
FROM vCodesWithPEs INNER JOIN vDeriveAvailabilityFromPE
ON vCodesWithPEs.PROD_PERM = vDeriveAvailabilityFromPE.PEID
INNER JOIN PE_PDP ON vCodesWithPEs.PROD_PERM = PE_PDP.PEID
) AS tb;
Error: The column 'PEID' was specified multiple times for 'tb'.
I am new to SQL.
The problem, as mentioned, is that you are selecting PEID from two tables, the solution is to specify which PEID do you want, for example
SELECT tb.*
FROM (
SELECT tb1.PEID,tb2.col1,tb2.col2,tb3.col3 --, and so on
FROM vCodesWithPEs as tb1 INNER JOIN vDeriveAvailabilityFromPE as tb2
ON tb1.PROD_PERM = tb2.PEID
INNER JOIN PE_PDP tb3 ON tb1.PROD_PERM = tb3.PEID
) AS tb;
That aside, as Chris Lively cleverly points out in a comment the outer SELECT is totally superfluous. The following is totally equivalent to the first.
SELECT tb1.PEID,tb2.col1,tb2.col2,tb3.col3 --, and so on
FROM vCodesWithPEs as tb1 INNER JOIN vDeriveAvailabilityFromPE as tb2
ON tb1.PROD_PERM = tb2.PEID
INNER JOIN PE_PDP tb3 ON tb1.PROD_PERM = tb3.PEID
or even
SELECT *
FROM vCodesWithPEs as tb1 INNER JOIN vDeriveAvailabilityFromPE as tb2
ON tb1.PROD_PERM = tb2.PEID
INNER JOIN PE_PDP tb3 ON tb1.PROD_PERM = tb3.PEID
but please avoid using SELECT * whenever possible. It may work while you are doing interactive queries to save typing, but in production code never use it.
Looks like you have the column PEID in both tables: vDeriveAvailabilityFromPE and PE_PDP. The SELECT statement tries to select both, and gives an error about duplicate column name.
You're joining three tables, and looking at all columns in the output (*).
It looks like the tables have a common column name PEID, which you're going to have to alias as something else.
Solution: don't use * in the subquery, but explicitly select each column you wish to see, aliasing any column name that appears more than once.
Instead of using * to identify collecting all of the fields, rewrite your query to explicitly name the columns you want. That way there will be no confusion.
just give new alias name for the column that repeats,it worked for me.....