nesting selects and refere to outer table - sql

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

Related

sql join using the below

I know I am doing something wrong, but both tables appear as joins.
This is my code:
SELECT
*
FROM
table1
LEFT OUTER JOIN
users ON users.id = (SELECT id
FROM table2
WHERE type = 'user') t t.id
If I had to a join on the other hand site, its feasible and doable, but for this type, I am not sure I can assign the value like this or not
I don't know if I totally understand the query, but if you are looking to use a join table to connect a many to many relationship try this:
SELECT *
FROM table1 t1
LEFT OUTER JOIN table2 on t1.id = t2.id AND t2.type = 'user'
LEFT OUTER JOIN users u on u.id = t2.id

How to do a full outer join

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

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

mysql JOIN ON IF()?

I am trying to use sql such as this:
SELECT t.*, t2.* FROM templates t
LEFT JOIN IF(t.t_type = 0,'templates_email',
IF(t.t_type = 1,'templates_sms','templates_fax')) t2
ON t.t_id = t2.t_id;
Is it possible to do something like that?
basically I want to join on one of three tables based on the value from the row.
Is this recommended if it is possible?
update
So,
basically the templates table is the table that contains all the information that every template must have, eg name, id, description
then you have the templates_x tables these tables contain the fields that are unique to each template type.
(There are quite a few and having a single table with null fields for those not applicable is not practical).
The tables are called templates_x however the appropriate x is stored in the templates table as an int flag.
The join between the templates_x tables and the templates table is through the t_id.
So what do you suggest?
Is it possible to do something like that?
No, you can't use dynamically assigned tables (join or otherwise) without using dynamic SQL syntax (See MySQL's PreparedStatement syntax).
This non-dynamic re-write of your pseudo-query assumes that the three template tables you join to all have the same number of columns, and the same data types:
SELECT t.*,
te.*
FROM TEMPLATES t
JOIN TEMPLATES_EMAIL te ON te.t_id = t.t_id
WHERE t.t_type = 0
UNION
SELECT t.*,
ts.*
FROM TEMPLATES t
JOIN TEMPLATES_SMS ts ON ts.t_id = t.t_id
WHERE t.t_type = 1
UNION
SELECT t.*,
tf.*
FROM TEMPLATES t
JOIN TEMPLATES_FAX tf ON tf.t_id = t.t_id
WHERE t.t_type NOT IN (0, 1)
Instead of a conditional join, you can join the data then select which field you want.
Example:
SELECT
CASE
WHEN t.type = 0 THEN [templates_email]
WHEN t.type = 1 THEN [templates_sms]
WHEN t.type = 2 THEN [templates_fax]
END AS [selected_field]
FROM
t
LEFT JOIN t1 ON t.t_id = t1.t_id
LEFT JOIN t2 ON t.t_id = t2.t_id
LEFT JOIN t3 ON t.t_id = t3.t_id
I'm afraid it would have to be something like this (if all tables have the same columns):
SELECT t.*, t2.* FROM templates t
LEFT JOIN templates_email t2
ON t.t_id = t2.t_id
WHERE t.t_type = 0
UNION
SELECT t.*, t2.* FROM templates t
LEFT JOIN templates_sms t2
ON t.t_id = t2.t_id
WHERE t.t_type = 1
UNION
SELECT t.*, t2.* FROM templates t
LEFT JOIN templates_fax t2
ON t.t_id = t2.t_id
WHERE t.t_type NOT IN (0,1)
Or like this:
SELECT t.*, t1.*, t2.*, t3.*
FROM templates t
LEFT JOIN templates_email t1
ON t.t_id = t1.t_id
AND t.type_id = 0
LEFT JOIN templates_sms t2
ON t.t_id = t2.t_id
AND t.type_id = 1
LEFT JOIN templates_fax t3
ON t.t_id = t3.t_id
AND t.type_id NOT IN (0,1)
.. and live with all your NULL columns.