I have a db2 query and I realized today I need to expand that query.
My table's already pretty complicated with joins, so I don't really want to add a union query. I want to do a full outer join.
At the moment, it's showing
SELECT
a.id
,a.city
,a.state
,case when a.thing = b.thing then a.thing else b.thing end
,sum( case when c.thing = 'thing' then 1 else 0 end)
,b.id
,b.name
FROM
a
INNER JOIN b -- I want to change this to FULL OUTER JOIN
ON a.id = b.id
LEFT JOIN c
ON a.id = c.id
LEFT JOIN (d
INNER JOIN e
ON d.id = e.id
)
WHERE
--logic
GROUP BY
--for the aggregate functions
ORDER BY
--logic
Can someone tell me when I try to do a full outer join, it says 'Full Outer Join is not supported for this query'? And how would I overcome that?
I think it's because of the other left joins.
It may not be able to combine the outer join with the left joins. You may have to make the outer join a subquery (also added some missing aliases and an ON clause):
SELECT
ab.a_id
,ab.city
,ab.state
,ab.thing
,sum( case when c.thing = 'thing' then 1 else 0 end)
,ab.b_id
,ab.name
FROM
(
SELECT
a.id a_id
,a.city
,a.state
,case when a.thing = b.thing then a.thing else b.thing end thing
,b.id b_id
,b.name
FROM
a
FULL OUTER JOIN b
ON a.id = b.id
) ab
LEFT JOIN c
ON ab.id = c.id
LEFT JOIN (d
INNER JOIN e
ON d.id = e.id
) f
ON ...
WHERE
--logic
GROUP BY
--for the aggregate functions
ORDER BY
--logic
Related
I want to combine all the related data using LEFT JOIN clause but if one of tables has no matched record from other table it will not show up. Can you check my queries it seems that there is missing or totally messed up. Here's my query.
SELECT*
FROM
MASTER_TBL
LEFT JOIN
(
SELECT*
FROM
TBLA A
LEFT JOIN
TBLB B
ON
A.ID=B.ID AND A.DESC=B.DESC
LEFT JOIN
TBLC C
ON
B.ID=C.ID AND B.DESC=C.DESC
LEFT JOIN
TBLD D
ON
C.ID=D.ID AND C.DESC=D.DESC
) E
ON
MASTER_TBL.ID=E.ID
The problem is that you are cascading the conditions across joins. For example, here are the join conditions for table d:
C.ID = D.ID AND C.DESC = D.DESC
For this to match, you need to have a matching row in C already.
As your query stands, it looks like you can use the id from the master table to search all the following tables. As for the desc columns, it looks like your best pick is to use that of table a.
So, consider:
select *
from master_tbl m
left join tbla a on a.id = m.id
left join tblb b on b.id = m.id and b.desc = a.desc
left join tblc c on c.id = m.id and c.desc = a.desc
left join tbld d on d.id = m.id and d.desc = a.desc
If all descs are not available in tablea, we could switch to full joins. The logic is more complicated to follow, but that would look like:
select *
from master_tbl m
full join tbla a on a.id = m.id
full join tblb b on b.id = m.id and b.desc = a.desc
full join tblc c on c.id = m.id and c.desc = coalesce(a.desc, b.desc)
full join tbld d on d.id = m.id and d.desc = coalesce(a.desc, b.desc, c.desc)
This approach uses UNION ALL to combine the letter named tables (tbla, tblb, tblc, tbld) into a CTE, common table expression. The combined table is then summarized by id, [desc] and crosstabulated (or pivoted) across the login columns. The pivoted result is then LEFT JOIN'ed to the master_tbl. Something like this.
with
tbl_cte(tbl, id, [login], [desc]) as (
select 'A', * from tbla
union all
select 'B', * from tblb
union all
select 'C', * from tblc
union all
select 'D', * from tblc),
pvt_cte(id, tbla_login, tblb_login, tblc_login, tbld_login, [desc]) as (
select id,
max(case when tbl='A' then [login] else null end) as tbla_login,
max(case when tbl='B' then [login] else null end) as tblb_login,
max(case when tbl='C' then [login] else null end) as tblc_login,
max(case when tbl='D' then [login] else null end) as tbld_login,
[desc]
from tbl_cte
group by id, [desc])
select mt.id, [name], country, [status], pc.tbla_login,
pc.tblb_login, pc.tblc_login, pc.tbld_login, pc.[desc]
from master_tbl mt
left join pvt_cte pc on mt.id=pc.id;
I am new in SQL, I have a basic question. I have 3 tables and 2 inner joins.
This is my SQL code:
select c.name, case when e.time > NOW() then 'Yes' else 'No' end AS "time"
from table1 as e
INNER JOIN table2 as a on e.id = a.id
INNER JOIN table3 as c on a.id = c.id
where e.conty= 'SAD'
GROUP BY c.name;
Error: must appear in the GROUP BY clause or be used in an aggregate function
Any field you want to retrieve must be contained in the GROUP BY clause of that query. You should include "time" in the GROUP BY clause or exclude it from the query.
select c.name, case when e.time > NOW() then 'Yes' else 'No' end AS "time"
from table1 as e
INNER JOIN table2 as a on e.id = a.id
INNER JOIN table3 as c on a.id = c.id
where e.name = 'JOHN'
GROUP BY c.name, time;
Use the e.time attribute in the GROUP BY clause.
select c.name, case when e.time > NOW() then 'Yes' else 'No' end AS "time"
from table1 as e
INNER JOIN table2 as a on e.id = a.id
INNER JOIN table3 as c on a.id = c.id
where e.name = 'JOHN'
GROUP BY c.name, e.time;
I am guessing that you want aggregation -- and the maximum time:
select c.name,
(case when max(e.time) > NOW() then 'Yes' else 'No' end) AS "time"
from table1 e join
table2 a
on e.id = a.id join
table3 c
on a.id = c.id
where e.name = 'JOHN'
group by c.name;
You don't need to group by name since you select only the rows with name = 'JOHN'.
If you want to select the row with the maximum time, do this:
select
'JOHN' name,
case when max(e.time) > NOW() then 'Yes' else 'No' end AS "time"
from table1 as e
INNER JOIN table2 as a on e.id = a.id
INNER JOIN table3 as c on a.id = c.id
where e.name = 'JOHN'
From everything I have learned about LEFT OUTER JOIN, the table you want to be nullable should be on the right side of the equals symbol. If this is the case, why do both of these queries return the same result:
SELECT *
FROM employees e
LEFT JOIN cars c ON c.employeeID=e.id AND c.name='Honda City'
WHERE c.id IS NULL
ORDER BY e.id ASC;
SELECT *
FROM employees e
LEFT JOIN cars c ON e.id=c.employeeID AND c.name='Honda City'
WHERE c.id IS NULL
ORDER BY e.id ASC;
Demo: http://sqlfiddle.com/#!15/46d00/2
Q1 uses A LEFT JOIN B ON A.id = B.id
Q2 uses A LEFT JOIN B ON B.id = A.id
You have changed the LHS and RHS of the items being compared in the ON clause, but the LEFT join is talking about which TABLE is on the left.
So to see a difference you would make Q2 use "B LEFT JOIN A ON A.id = B.id"
In this query other than 5 join tables i am trying to use 6th table "Days" to compare value with three tables in joins. but it give me error that i cant use subquery in joins.
select
a.ID, a.Name, a.AMT, b.Address, c.Date, c.Pay, d.Check
from
Table1 a
left outer join Table2 b on a.ID = b.ID
left outer join Table3 c on a.ID = c.ID and c.Date= (select Derived_date from Days where TODAY_DATE = TO_DATE(SYSDATE, 'YYYY/MM/DD'))
left outer join Table4 d on a.ID = d.ID and d.Date= (select Derived_date from Days where TODAY_DATE = TO_DATE(SYSDATE, 'YYYY/MM/DD'))
left outer join Table5 e on a.ID = e.ID and e.Date= (select Derived_date from Days where TODAY_DATE = TO_DATE(SYSDATE, 'YYYY/MM/DD'))
Trying to use a subselect in an ON clause isn't going to work to well. You'd need to JOIN back to it like you would any other table. Since your subselect is the same for every single JOIN, I'd put that in a (temp?) table first so you can JOIN to it normally and not have to SELECT the same data three times.
CREATE TABLE Derived_Dates AS SELECT Derived_date FROM Days WHERE TODAY_DATE = TO_DATE(SYSDATE, 'YYYY/MM/DD')
SELECT a.ID, a.Name, a.AMT, b.Address, c.Date, c.Pay, d.Check
FROM Table1 a LEFT OUTER JOIN Table2 b on a.ID = b.ID
LEFT OUTER JOIN Table3 c ON a.ID = c.ID
LEFT OUTER JOIN Table4 d ON a.ID = d.ID
LEFT OUTER JOIN Table5 e ON a.ID = e.ID
INNER JOIN Dervied_date dt ON c.Date = dt.Derived_date
AND d.Date = dt.Derived_date
AND e.Date = dt.Derived_date
Here's how you can do it with your subselect:
SELECT a.ID, a.Name, a.AMT, b.Address, c.Date, c.Pay, d.Check
FROM Table1 a LEFT OUTER JOIN Table2 b on a.ID = b.ID
LEFT OUTER JOIN Table3 c ON a.ID = c.ID
LEFT OUTER JOIN Table4 d ON a.ID = d.ID
LEFT OUTER JOIN Table5 e ON a.ID = e.ID
INNER JOIN (SELECT Derived_date FROM Days WHERE TODAY_DATE = TO_DATE(SYSDATE, 'YYYY/MM/DD')) dt ON c.Date = dt.Derived_date
AND d.Date = dt.Derived_date
AND e.Date = dt.Derived_date
Instead of JOINing back to your derived dates, you could also just use a WHERE clause. You have some options, and you might want to make some changes for your particular implementation, but this is more or less how I'd approach this.
Working on Oracle: I am attempting to do an inner self join, with a where clause, then take that result and do a left outer join on it:
(select * from table1 A
inner join
select * from table1 B
on A.id = B.id
where
A.id is not null and B.id is not null) C
left outer join
select * from table2 D
on C.id = D.id
Somehow I am syntactically challenged and can't make this work. Can't seem to find the right syntax anywhere.
Just the put the where clause at the end. The database will get it right:
select *
from table1 A
inner join table1 B on A.id = B.id
left join table2 D on D.id = A.id
where A.id is not null
In this case, we can take advantage of the logical transitive property for your id column joins and where clause.
Your second join needs to be joined to a query add a select * from at the beginning
select * from (select * from table1 A
inner join
select * from table1 B
on A.id = B.id
where
A.id is not null and B.id is not null) C
left outer join
select * from table2 D
on C.id = D.id