I cannot get this LEFT JOIN to work (I don't understand joins) - sql

These queries both get results:
SELECT * FROM Table1 WHERE Criteria = '5'
SELECT * FROM Table1 WHERE Criteria = '3'
This query gets results:
SELECT *
FROM Table1 p, Table2 m
WHERE p.UID = m.ID
AND Criteria = '5'
This query does not:
SELECT *
FROM Table1 p, Table2 m
WHERE p.UID = m.ID
AND Criteria = '3'
I am trying to convert these to a proper join which returns results even if there are no records in the right table.
I have tried the following
SELECT *
FROM Table1 p LEFT JOIN Table2 m ON p.UID = m.ID
WHERE p.Criteria = '3'
AND m.OtherCriteria = 'Moron'
--0 results
My limited understanding was that LEFT join is what I needed. I want data from the left table even if there is no data in the right table that matches. Since this didn't work I also tried right join, left outer join, right outer join and full join. None returned results.
What am I missing?

This is too long for a comment. Your query:
SELECT *
FROM Table1 p LEFT JOIN
Table2 m
ON p.UID = m.ID AND p.Criteria = '3';
Should be returning a row for all rows in table1. If there is no match, then the values will be NULL for table2. This is easily demonstrated: Here is a MySQL example on SQL Fiddle. Because this is standard behavior, it should work on almost any database.
Note that this query is quite different from this one:
SELECT *
FROM Table1 p LEFT JOIN
Table2 m
ON p.UID = m.ID
WHERE p.Criteria = '3';
This query returns no rows, because no rows match the WHERE clause. The filtering happens (conceptually) after the LEFT JOIN.
I changed the code in the SQL Fiddle slightly, so that query is:
select *
from (select 5 as criteria, 1 as id union all
select 6, 1 union all
select 7, 2
) table1 left join
(select 1 as id, 'x' as x
) table2
on table1.id = table2.id and criteria = 3;
As a note: you should always use explicit join syntax. Simple rule: Never use commas in the FROM clause.
If your database is returning no rows, then it is behaving in a non-standard manner or your interface has decided to filter the rows for some reason.

Related

H2 does not allow to execute select with join inside set

I want to fill all columns in one table basing on columns from select with left join from two others:
update TAB1 as P
set P.COL1 = (
select CODE from (
select * from TAB2 as A left outer join TAB3 as T on A.TAGID = T.ID
) as O
where P.ACTID = O.ACTID
);
It works properly on Oracle, but when i want to execute it on h2 I got this error:
Duplicate column name "ID"; SQL statement
I dont know where is a problem. I could'nt find any solution for that.
Thx for the answers
This statement is your problem:
(select * from TAB2 as A left outer join TAB3 as T on A.TAGID = T.ID)
Presumably, you have an ID in both tables, so the SELECT * returns two columns named ID. I'm surprised this works in Oracle -- but perhaps Oracle optimizes the code because the IDs are not needed.
Just return the value you want:
(select ?.CODE from TAB2 as A left outer join TAB3 as T on A.TAGID = T.ID)
The question mark is either A or T, depending on which table the value comes from.

Conditionally joining from multiple tables

Does SQL allow some form of conditional "table choosing" within the Join statement? ie. selecting a different table to join based on a predefined variable/condition.
define var = 1
select *
from tbl
join (case when &var=1 then tblA when &var=2 then tblB else tblC end) a on tbl.id = a.id
The error I get when attempting this method is ORA-00905: missing keyword.
No. Neither SQL nor Oracle allow this, unless you use dynamic SQL.
Assuming the tables have the same columns, you could write this logic as:
select *
from tbl join
(select a.* from tblA where &var = 1 union all
select b.* from tblB where &var = 2 union all
select c.* from tblC where &var not in (1, 2)
) abc
on tbl.id = abc.id;
You still need to specify all joins ahead of time and they would have to be left outer joins, but you can rewrite your statement like this. This way will work regardless of the number of fields in each of the tables (requirement for the union), and if they are named differently then you can access the appropriate field by name.
DECLARE #var int
SET #var=1
select tbl.*, tblA.ShippingName, tblB.BillingName, tblC.OtherName
from tbl
left outer join tblA on tbl.id = tblA.id and #var = 1
left outer join tblB on tbl.id = tblB.id and #var = 2
left outer join tblC on tbl.id = tblC.id and #var = 3

SQL Full Outer Join : Whats the difference in these queries?

Lets suppose I have a full outer join query written in these styles:
SELECT * FROM Table_A
FULL OUTER JOIN Table_B ON (Table_A.Col1 = Table_B.Col1 AND Table_B.iscurrent=1)
Versus
SELECT * FROM Table_A
FULL OUTER JOIN (Select * FROM Table_B Where iscurrent=1) AS Table_B
ON (Table_A.Col1 = Table_B.Col1)
Both are producing different results in my database (Azure SQL DB).
How come?
Why are they returning different results? Because they are different queries. FULL OUTER JOIN is very tricky. Let me explain.
The result set from the first query has rows from all the rows in both tables, even those where Table_B.iscurrent <> 1. If this is not true, then the corresponding columns will be NULL, but the row will be there.
The result set from the second query will have no rows were Table_B.iscurrent <> 1. These are filtered out before the FULL OUTER JOIN, so they are not among the rows being counted.
In general, I find that FULL OUTER JOIN is very rarely needed. I do use it, but quite rarely. Typically LEFT JOIN or UNION ALL does what I really want.
On the second only rows with Where Table_B.iscurrent = 1 are included.
In the first you have all the rows in Table_B but they just don't connect to Table_A if iscurrent <> 1.
SELECT *
FROM Table_A
FULL OUTER JOIN Table_B
ON Table_A.Col1 = Table_B.Col1
AND Table_B.iscurrent = 1
SELECT *
FROM Table_A
FULL OUTER JOIN ( Select *
FROM Table_B
Where iscurrent = 1
) AS Table_B
ON Table_A.Col1 = Table_B.Col1

Combining 2 select statements

I have 2 select statements having a common column POL.SP_NUM which I wish to combine. I am new to SQL and haven't the slightest clue how to go about with the same.
Query 1:
select POL.SP_NUM POL#
, POL.ASSET_NUM COV#
, count(distinct(POLX.ATTRIB_06)) COUNT_ADDENDA
, count(distinct(POLX.ATTRIB_07)) COUNT_CERT
, sum(POL.QTY) SI
from S_ASSET POL
, S_ASSET_X POLX
Where POL.ROW_ID = POLX.ROW_ID
and POL.SP_NUM in ('000','111','222')
group by
POL.SP_NUM
, POL.ASSET_NUM
Query 1 output:
POL# COV# COUNT_ADDENDA COUNT_CERT SI
000 856 2 0 1000
111 123 0 0 500
222 567 0 1 2000
Query 2:
select POL#, sum(DOCI)
from (
select POL.SP_NUM POL#, sum(Q.AMT + POL.AMT) DOCI
from S_ASSET POL
, S_QUOTE_ITEM Q
where POL.X_QUOTE_ID = Q.ROW_ID
and POL.SP_NUM in ('000','111','222')
group by POL.SP_NUM
UNION ALL
select POL.SP_NUM POL#, sum(QXM.AMT) DOCI
from S_ASSET POL
, S_QUOTE_ITEM Q
, S_QUOTE_ITEM_XM QXM
where POL.X_QUOTE_ID = Q.ROW_ID
and Q.ROW_ID = QXM.PAR_ROW_ID
and POL.SP_NUM in ('000','111','222')
group by POL.SP_NUM
)
group by POL#
Query 2 output:
POL# sum(DOCI)
000 90
111 0
222 10
Desired output:
POL# COV# COUNT_ADDENDA COUNT_CERT SI sum(DOCI)
000 856 2 0 1000 90
111 123 0 0 500 0
222 567 0 1 2000 10
If there is a better way to code this? Suggestions are welcome.
This is no answer to the question, but an answer to the request to explain the join types made in the comments setion.
INNER JOIN (or short: JOIN)
select * from t1 join t2 on t1.colx = t2.coly
only gives you matches. This is the most common join. You could replace the ON clause with a USING clause in case the columns in the ON clause have the same names in the tables. Sometimes usefull to quickly write a query, but I would generally not recommend USING.
LEFT OUTER JOIN (or short: LEFT JOIN)
select * from t1 left join t2 on t1.colx = t2.coly
gives you all t1 records, no matter whether they have a math in t2. So when there is a match or more for a t1 record, then you join these just as wih an inner join, but when a t1 record has no match in t2 then you get the t1 record along with an empty t2 record (all columns are NULL, even the columns you used in the ON clause, which is t2.coly in above example). In other words: you get all records you'd get with an inner join plus all t1 records that have no match in t2.
You can also use a RIGHT JOIN so you'd keep t2 records when there is no t1 match:
select * from t1 right join t2 on t1.colx = t2.coly
but this is regarded less readable by many people, so better don't use right outer joins, but simply swap tables then:
select * from t2 left join t1 on t1.colx = t2.coly
FULL OUTER JOIN (or short: FULL JOIN)
select * from t1 full outer join t2 on t1.colx = t2.coly
this gives you all records from both t1 and t2, no matter whether they have a match in the other table or not. Again: You get all records you'd get with an inner join plus all t1 with no t2 match plus all t2 with no t1 match.
When having several full outer joins the USING clause can come in handy:
select product, sum(p1.amount), sum(p2.amount), sum(p3.amount)
from p1
full outer join p2 using (product)
full outer join p3 using (product);
CROSS JOIN
A cross join joins a table without any criteria, so as to combine each of its records with each of the records already present. This is used to get all combinations and usually followed by a left outer join:
select products.product_id, regions.region_id, count(*)
from products
cross join regions
left join sales on sales.product_id = products.product_id
and sales.region_id = regions.region_id
group by products.product_id, regions.region_id
order by products.product_id, regions.region_id;
This gives you all possible combinations of products and regions and counts the sales therein. So you get a result record even for product / region combinations where nothing was sold (i.e. no entry in table sales).
NATURAL JOIN
looks at common column names to magically join tables. My simple advice: never use this join type.
ANTI JOIN
This is not a join type actually, but a usage of a join, namely an outer join. Here you want to get all records from a table except the matches. You achieve this by outer-joining the tables and then removing matches in the where clause.
select t1.*
from t1
left join t2 on t1.colx = t2.coly
where t2.coly is null;
This looks queer, because we have EXISTS (and IN) to check for existence:
select *
from t1
where not exists (select * from t2 where t2.coly = t1.colx);
So why would one obfuscate things and use the anti join pattern instead? It is a trick used on weak DBMS. When a DBMS is written, joins are the most important thing and the developers of the DBMS put all their effort into making them fast. They may neglect EXISTS and IN at first and only later care about their performance. So it may help then to use a join technique (the anti join) instead. My recommendation: Only use the anti join pattern when running into performance issues with a straight-forward query. So far I've never had to use anti joins it in more than twenty years. (It's good to have that option though. And it's good to know about them, so as to not be confused when stumbling upon such query some time :-)
You can join the queries:
select *
from (your query 1 here) query1
join (your query 2 here) query2 on query2.pol# = query1.pol#;
The same with WITH clauses:
with query1 as (your query 1 here),
query2 as (your query 2 here)
select *
from query1
join query2 on query2.pol# = query1.pol#;

Outer Join with Where returning Nulls

Hi I have 2 tables. I want to list
all records in table1 which are present in
table2
all records in table2 which are not present in table1 with a where condition
Null rows will be returned by table1 in second condition but I am unable to get the query working correctly. It is only returning null rows
SELECT
A.CLMSRNO,A.CLMPLANO,A.GENCURRCODE,A.CLMNETLOSSAMT,
A.CLMLOSSAMT,A.CLMCLAIMPRCLLOSSSHARE
FROM
PAKRE.CLMCLMENTRY A
RIGHT OUTER JOIN (
SELECT
B.CLMSRNO,B.UWADVICETYPE,B.UWADVICENO,B.UWADVPREMCURRCODE,
B.GENSUBBUSICLASS,B.UWADVICENET,B.UWADVICEKIND,B.UWADVYEAR,
B.UWADVQTR,B.ISMANUAL,B.UWCLMNOREFNO
FROM
PAKRE.UWADVICE B
WHERE
B.ISMANUAL=1
) r
ON a.CLMSRNO=r.CLMSRNO
ORDER BY
A.CLMSRNO DESC;
Which OS are you using ?
Table aliases are case sensistive on some platforms, which is why your join condition ON a.CLMSRNO=r.CLMSRNO fails.
Try with A.CLMSRNO=r.CLMSRNO and see if that works
I'm not understanding your first attempt, but here's basically what you need, I think:
SELECT *
FROM TABLE1
INNER JOIN TABLE2
ON joincondition
UNION ALL
SELECT *
FROM TABLE2
LEFT JOIN TABLE1
ON joincondition
AND TABLE1.wherecondition
WHERE TABLE1.somejoincolumn IS NULL
I think you may want to remove the subquery and put its columns into the main query e.g.
SELECT A.CLMSRNO, A.CLMPLANO, A.GENCURRCODE, A.CLMNETLOSSAMT,
A.CLMLOSSAMT, A.CLMCLAIMPRCLLOSSSHARE,
B.CLMSRNO, B.UWADVICETYPE, B.UWADVICENO, B.UWADVPREMCURRCODE,
B.GENSUBBUSICLASS, B.UWADVICENET, B.UWADVICEKIND, B.UWADVYEAR,
B.UWADVQTR, B.ISMANUAL, B.UWCLMNOREFNO
FROM PAKRE.CLMCLMENTRY A
RIGHT OUTER JOIN PAKRE.UWADVICE B
ON A.CLMSRNO = B.CLMSRNO
WHERE B.ISMANUAL = 1
ORDER
BY A.CLMSRNO DESC;