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.
Related
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
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
I am attempting to use multiple columns in my join like this:
FROM Table1 t
INNER JOIN Table2 s ON t.number = s.number OR t.letter = s.letter
Both of these tables have several hundred thousand rows of data and it is running infinitely.
Any ideas?
You mean something like:
FROM Table1 t
INNER JOIN Table2 s ON case
when t.number = s.number then 1
when t.letter = s.letter then 1
else 0 end = 1
The first matching condition wins.
One possibility is to use left join and fix the rest of the query:
FROM Table1 t LEFT JOIN
Table2 sn
ON t.number = sn.number LEFT JOIN
Table2 sl
ON t.letter = sl.letter and sn.number is null
For performance, you want indexes on Table2(number) and Table2(letter).
ORs are usually produce bad performance. I would go for:
SELECT *
FROM Table1 t
INNER JOIN Table2 s ON t.number = s.number
UNION
SELECT *
FROM Table1 t
INNER JOIN Table2 s ON t.letter = s.letter
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
How I can join this queries to single select (without temp table)?
SELECT t2.value,
t1.value
FROM table0 t1
INNER JOIN table1 t3 on t1.idrelation = t3.id and t3.idparent=#id
INNER JOIN table2 t2 on t2.idversion = t3.idchild and t2.name = 'FOO'
ORDER BY t1.value
SELECT SELECT COALESCE(t4._NAME+','+'')
FROM table1 t1
JOIN table1 t2 on t2.idparent = t1.idchild
JOIN table1 t3 on t3.idparent = t2.idchild
JOIN table3 t4 on t4._ID = t3.idchild
WHERE t1.idparent = #id
AND t4._TYPE ='TXT_CAT'
Something like this would help (once you can tell the columns on which you want to join):
select *
from
(
QUERY 1
) q1
join
(
QUERY 2
) q2
on q1.key1 = q2.key2
If you want to join them, there has to be common or uncommon ground.
Putting the 2 selects together is the easy part when you join the resultant sets, but unless you want all permutations of Ans1 and Ans2, then it is wise to determine some sort of where clause to allow it to be more effecient, and narrow it down for you.
If you give more table information, We could be able to adjust and give you something further, but that is the best we can do without taking arbitrary guesses as to what you are trying to accomplish here.
One thing i can part unto you:
Select A.name, B.id from (Select A.name, A.date from A) join (Select B.id, B.date from B) on A.date = B.date;