How to do a full outer join - sql

I set the THEATRES size using THEATRES.NUMOFROWS, THEATRES.NUMOFCOLS and each SEAT.SEATNO is tied to THEATRES.ID and SHOWTIMES.ID is tied to THEATRES.ID and TICKET_ITEMS are tied to SHOWTIMES.ID
I want to display all the values by joining the table using where clause for showtime.id. I know outer join will display null on non-matching but my query only shows one records.
SELECT
SHOWTIMES.ID AS SHOWTIMESID,
SHOWTIMES.THEATREID,
THEATRES.THEATRENAME,
THEATRES.NUMOFROWS,
THEATRES.NUMOFCOLS,
SEAT.SEATNO AS SEATLABEL,
SEAT.ROWID,
SEAT.COLUMNID,
TICKET_ITEMS.SEATNO,
TICKET_ITEMS.TICKETCODE
FROM
SHOWTIMES FULL OUTER JOIN TICKET_ITEMS ON SHOWTIMES.ID =TICKET_ITEMS.SHOWTIMESID
FULL OUTER JOIN THEATRES ON SHOWTIMES.THEATREID = THEATRES.ID
FULL OUTER JOIN SEAT ON SEAT.SEATNO = TICKET_ITEMS.SEATNO
WHERE
SHOWTIMES.ID = 1
;

If you are using any kind of OUTER JOIN and you refer to a column in the WHERE you need to handle NULLs. If you don't, you turn the JOIN into an implicit INNER JOIN. Take this simple example:
WITH T1 AS(
SELECT ID, SomeString
FROM (VALUES(1,'abc'),(2,'def')) V(ID, SomeString)),
T2 AS(
SELECT ID, fID, AnotherString
FROM (VALUES(1,1,'asd'),(2,1,'asdased')) V(ID, fID, AnotherString))
SELECT *
FROM T1
LEFT JOIN T2 ON T1.ID = T2.ID
WHERE T2.AnotherString = 'asd';
You might expect to get 2 rows here, one for where T1.ID is 1 with a joined row and 1 for T1.ID is 2, but with no joined rows. That isn't the case due to the WHERE. The correct solution here would be to move the WHERE to the ON:
WITH T1 AS(
SELECT ID, SomeString
FROM (VALUES(1,'abc'),(2,'def')) V(ID, SomeString)),
T2 AS(
SELECT ID, fID, AnotherString
FROM (VALUES(1,1,'asd'),(2,1,'asdased')) V(ID, fID, AnotherString))
SELECT *
FROM T1
LEFT JOIN T2 ON T1.ID = T2.ID
AND T2.AnotherString = 'asd';
With what you have, you can't do that, as you're using the base table, thus you'll need handle the NULL by changing your WHERE to:
WHERE SHOWTIMES.ID = 1 OR SHOWTIMES.ID IS NULL;

I imagine that your database has proper foreign key relationships set up -- so the theater id in one table is a valid id.
If so, you don't need full join. In fact, it is very rarely needed. I suspect that inner joins are sufficient (but that is the results you are getting).
If you want all theaters with the appropriate shows -- if any -- then use left join and start with the theaters:
select st.ID AS SHOWTIMESID, st.THEATREID,
th.THEATRENAME, th.NUMOFROWS, th.NUMOFCOLS,
s.SEATNO AS SEATLABEL, s.ROWID, s.COLUMNID,
ti.SEATNO, ti.TICKETCODE
from theatres th left join
showtimes st
on st.theatreid = th.id and st.id = 1 left join
ticket_items ti
on st.ID =ti.showtimesid left join
seat s
on s.seatno = ti.seatno

Related

BigQuery Deduplicate rows - No unique columns

I have a bigquery table which is a result of multiple left join tables.
The results are duplicated because of the left join (cartesian product)
How do I de-duplicate the rows so I only see one record?
SELECT T1.Col1,T1.Col2,........
T2.Col1,T2.Col2,........
T3.Col1,T3.Col3,........
T5.Col1,T5.Col2,........
T7.Col1.......
FROM `TABLE1` as T1
LEFT JOIN
`TABLE`as T2 ON T1.CUSTOMER_CODE = T2.CUSTOMER_CODE
LEFT JOIN
`TABLE3` as T3 ON (T1.MIAL_CODE) = T3.MIAL_CODE
LEFT JOIN
`TABLE5` as T5
ON T1.WORK_CODE = T5.WORK_CODE
LEFT JOIN
`TABLE7` as T7
ON T1.CA_DATE = T7.date
ORDER BY CA_DATE
Use DISTINCT:
select distinct *
from mytable
or create a new table:
create or replace table my_new_table
as
select distinct *
from mytable
I used GROUP BY and it worked fine to get rid of duplicates
SELECT T1.Col1,T1.Col2,........
T2.Col1,T2.Col2,........
T3.Col1,T3.Col3,........
T5.Col1,T5.Col2,........
T7.Col1.......
FROM `TABLE1` as T1
LEFT JOIN
`TABLE`as T2 ON T1.CUSTOMER_CODE = T2.CUSTOMER_CODE
LEFT JOIN
`TABLE3` as T3 ON (T1.MIAL_CODE) = T3.MIAL_CODE
LEFT JOIN
`TABLE5` as T5
ON T1.WORK_CODE = T5.WORK_CODE
LEFT JOIN
`TABLE7` as T7
ON T1.CA_DATE = T7.date
GROUP BY T1.Col1,T1.Col2,........
T2.Col1,T2.Col2,........
T3.Col1,T3.Col3,........
T5.Col1,T5.Col2,........
T7.Col1.......
ORDER BY CA_DATE

Sql join a table if rows exists otherwise switch to another table

considering we have the following query :
SELECT ca.Uid Numb,
ag.Code Cd,
ag.Name agn,
ca.TypeId tt
FROM dbo.Event ce
OUTERAPPLY
(SELECT*FROM dbo.Table1 tca WHERE tca.Uid= ce.Cuid) ca
OUTERAPPLY
(SELECT*FROM dbo.Table2 tct WHERE tct.Uid= ca.TypeId) ct
OUTERAPPLY
(SELECT*FROM dbo.Table3 ta WHERE ta.Id = ca.AgId) ag
OUTERAPPLY
(SELECT*FROM dbo.Table4 tsa WHERE tsa.Uid= ce.SId) ser
OUTERAPPLY
(
--- if Rows exists in this table take it
SELECT *
FROM dbo.Table5 ttra
WHERE ttra.ReferenceId = ce.TransactionRef
--- Otherwise use this table
SELECT *
FROM dbo.Table6 ttra
WHERE ttra.ReferenceId = ce.TransactionRef
) trx
WHERE trx.ApprovalDateTime ISNOTNULL
what i want basically on the outer apply to takes a table5 if rows exists in it using the where ttra.ReferenceId = ce.TransactionRef
else use Table6 using the same condition
It looks like you suffer from missing spaces, so I inserted them.
From the way OUTER APPLY is used, it is better (more readable) to use LEFT JOIN. OUTER APPLY is useful if the right part needs to be evaluated for every left-row-value separately, which in the first 4 joins does not seem to be the case.
I'm not sure about the Table5+Table6 join, so I left it in there; but maybe it can also be converted to a LEFT JOIN.
Furthermore I used UNION + NOT EXISTS to join the rows from Table5 with rows from Table6-if-Table5-gives-no-results.
Resulting code:
SELECT ca.Uid Numb,
ag.Code Cd,
ag.Name agn,
ca.TypeId tt
FROM dbo.Event ce
LEFT JOIN dbo.Table1 ca ON ca.Uid = ce.Cuid
LEFT JOIN dbo.Table2 ct ON ct.Uid = ca.TypeId
LEFT JOIN dbo.Table3 ag ON ag.Id = ca.AgId
LEFT JOIN dbo.Table4 se ON se.Uid = ce.SId
OUTER APPLY
(
--- if Rows exists in this table take it
SELECT *
FROM dbo.Table5 t5
WHERE t5.ReferenceId = ce.TransactionRef
UNION
--- Otherwise use this table
SELECT *
FROM dbo.Table6 t6
WHERE t6.ReferenceId = ce.TransactionRef
AND NOT EXISTS (SELECT 1 FROM dbo.Table5 WHERE ReferenceId = ce.TransactionRef)
) trx
WHERE trx.ApprovalDateTime IS NOT NULL

Joining tbl1 to select statement twice with join to tbl2 that also joins to tbl3

I'm using SQL server manger.
I have 3 tables
I need a query that pulls t1 ands add an Origin Basin and a Destination Basin.
So far I have the following:
select T1.[Country (destination)], T3.AreaName
From T1
left outer join T2 on
T1.[Country (destination)] = T2.CountryName
inner join T3 on
T2.AreaID = T3.AreaID
inner join T3 on
T2.AreaID = T3.AreaID
Which returns:
Country | Area
However, I'm having trouble doing this for the second country column. I believe you use aliases. I've tried:
select (select AreaName
FROM T3
where T3.AreaID = T2.AreaID) as 'Area Imp',
(select AreaID
From T2
where T2.CountryName = T1.[Country (origin)]) as 'x',
(select AreaID
From T2
where T2.CountryName = T1.[Country (destination)]) as 'y'
FROM T1
But I can't get it to work.
This is what you need to do:
select t1.date, t1.country_destination, t1.country_origin, destination_area.AreaName as area_destination, origin_area.AreaName as area_origin
from t1 as t1 join t2 as destination on t1.country_destination = destination.countryname
join t2 as origin on t1.country_origin = origin.countryname
join t3 as destination_area on t2.areaid = destination_area.areaid
join t3 as origin_area on t2.areaid = origin_area.areaid
You will need to join with the same table twice, both for t2 and t3 so that you get the matching records for your needs.
It helps usually to put aliases that match the purpose of the join (in this case, destination and origin) when writing the query.
I think what you're trying to do is something like this:
select T1.*, T3dest.AreaName, T3orig.AreaName
From
T1
inner join
T2 T2dest on
T1.[Country (destination)] = T2dest.CountryName
inner join
T3 T3dest on
T2dest.AreaID = T3dest.AreaID
inner join
T2 T2orig on
T1.[Country (origin)] = T2orig.CountryName
inner join
T3 T3orig on
T2orig.AreaID = T3orig.AreaID
Note that I've switched to inner joins throughout, at the moment. If you do want left join semantics, you either need to use those for all of the joins to the T2 and T3 tables or you need to change the join order (so that the relevant T3 joins to the T2 tables occur before the attempted join with T1). It's not clear from the sample data if that's required, however.
Try this, You would still want to join on area id's
select T1.Date,T1.[Country (destination)], null [Country (origin)], T3.AreaName [AreaName(Destination)], null [AreaName(Origin)]
From T1
left outer join T2 on
T1.[Country (destination)] = T2.CountryName
inner join T3 on
T2.AreaID = T3.AreaID
union all
select T1.Date,null [Country (destination)], t1.[Country (origin)], Null [AreaName(Destination)], t3. [AreaName(Origin)]
From T1
left outer join T2 on
T1.[Country (Origin)] = T2.CountryName
inner join T3 on
T2.AreaID = T3.AreaID

INNER JOIN within a LEFT JOIN clause

I was given a query that uses some very weird syntax for a join and I need to understand how this join is being used:
SELECT
T1.Acct#
, T2.New_Acct#
, T3.Pool#
FROM DB.dbo.ACCT_TABLE T1
LEFT JOIN DB.dbo.CROSSREF_TABLE T2
INNER JOIN DB.dbo.POOL_TABLE T3
ON T2.Pool# = T3.Pool#
ON T1.Acct# = T2.Prev_Acct#
T1 is a distinct account list
T2 is a distinct account list for each Pool #
T3 is a distinct pool list (group of accounts)
I need to return the previous account number held in T2 for each record in T1. I also need the T3 Pool# returned for each pool.
What I'm trying to understand is why someone would write the code this way. It doesn't make sense to me.
A little indenting will show you better what was intended
SELECT
T1.Acct#
, T2.New_Acct#
, T3.Pool#
FROM DB.dbo.ACCT_TABLE T1
LEFT JOIN DB.dbo.CROSSREF_TABLE T2
INNER JOIN DB.dbo.POOL_TABLE T3
ON T2.Pool# = T3.Pool#
ON T1.Acct# = T2.Prev_Acct#
This is a valid syntax that forces the join order a bit. Basically it is asksing for only the records in table T2 that are also in table T3 and then left joining them to T1. I don't like it personally as it is confusing for maintenance. I would prefer a derived table as I find those much clearer and much easier to change when I need to do maintenance six months later:
SELECT
T1.Acct#
, T2.New_Acct#
, T3.Pool#
FROM DB.dbo.ACCT_TABLE T1
LEFT JOIN (select T2.New_Acct#, T3.Pool#
FROM DB.dbo.CROSSREF_TABLE T2
INNER JOIN DB.dbo.POOL_TABLE T3
ON T2.Pool# = T3.Pool#) T4
ON T1.Acct# = T4.Prev_Acct#
An OUTER APPLY would be clearer here:
SELECT
T1.Acct#,
T4.New_Acct#,
T4.Pool#
FROM DB.dbo.ACCT_TABLE T1
OUTER APPLY
(
SELECT
T2.New_Acct#,
T3.Pool#
FROM DB.dbo.CROSSREF_TABLE T2
INNER JOIN DB.dbo.POOL_TABLE T3 ON T2.Pool# = T3.Pool#
WHERE T1.Acct# = T4.Prev_Acct#
) T4

nesting selects and refere to outer table

I have the following sql statement. I am pulling data from a flat tree structure where i want to select a single follower matching abos_daten.erstellt = (select MAX(erstellt)...
The problem is in order to select the correct MAX(erstellt) I need the following condition where t2.parent_id = t1.parent_id. Unfortunatly t1 can't be bound because it referes to the outer select statement. It seems to create a circle.
select * from trees as t1 inner join abos_daten as starter on t1.parent_id = starter.abonr
right outer join
(select * from trees as t3 inner join abos_daten on t3.child_id = abos_daten.abonr
where abos_daten.erstellt = (select MAX(erstellt) from abos_daten inner join trees as t2 on t2.child_id = abos_daten.abonr
where t2.parent_id = t1.parent_id and abos_daten.status_id <> 147
)
) as follower on t1.child_id = follower.abonr
Does anybody know how to solve this? Kind regards,
jonatan
To start with, t1 doesn't actually refer to the outer select statement; it refers to another entity in the from clause. As it happens, SQL server has a syntax that specifically allows this kind of functionality: cross apply/outer apply. To use this in you situation, you'd want something like this (untested since I can't re-create your tables):
select *
from trees as t1
inner join abos_daten as starter
on t1.parent_id = starter.abonr
outer apply (select MAX(erstellt) as max_erstellt
from abos_daten
inner join trees as t2
on t2.child_id = abos_daten.abonr
where t2.parent_id = t1.parent_id
and abos_daten.status_id <> 14) as t_m
right outer join (select *
from trees as t3
inner join abos_daten
on t3.child_id = abos_daten.abonr) as follower
on t1.child_id = follower.abonr
and t_m.max_erstellt = follower.erstellt