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

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

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

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

SQL Server - use columns from the main query in the subquery

Is there any way to get a column in real time, from a main query, and use it in a subquery?
Something like this: (Use A.item in the subquery)
SELECT item1, *
FROM TableA A
INNER JOIN
(
select *
from TableB B
where A.item = B.item
) on A.x = B.x;
Ok, here is the real thing:
I need to modify this existing query. It worked before, but now that the database changed, I need to do some modifications, add some comparisons. As you can see there are a lot of JOINS, and one of them is a subquery. I need to add a comparison from a column from the main query (from the table T0 for example) to the subquery (like this: T6.UnionAll_Empresa = T0.UnionALl_Empresa)
Select T0.UnionAll_Empresa,<STUFF>
from [UNION_ALL_BASES]..OINV T0 with (nolock)
inner join [UNION_ALL_BASES]..INV6 T1 with (nolock) on t0.DocEntry = t1.DocEntry and t0.UnionAll_Empresa = t1.UnionAll_Empresa
inner join
(
select
t1.CompanyID,
T2.CompanyDb,
t1.OurNumber,
T6.BankCode,
T6.BankName,
T3.[Description] Situation,
T1.[Status],
T5.Descrption nomeStatus,
T1.Origin,
T1.DocEntry,
T1.DocType,
T1.ControlKey,
T1.CardCode,
T4.[Description] ContractBank,
T1.PayMethodCode,
T1.DueDate,
T1.DocDate,
T1.InstallmentID,
T1.InstallmentValue,
T1.Correction,
T1.InterestContractural,
T1.FineContract,
T1.ValueAbatment,
T1.ValueDiscount,
T1.ValueFineLate,
T1.ValueInterestDaysOfLate,
T1.OtherIncreases,
T1.ValueInWords,
T1.ValueDocument,
T1.DigitalLine,
T1.Document
from [IntegrationBank]..BillOfExchange T1 with (nolock)
inner join [InterCompany2]..CompanyHierarchy T2 with (nolock) on T1.CompanyID = T2.ID
left join [IntegrationBank]..BillOfExchangeSituation T3 with (nolock) on T1.Situation = T3.ID
inner join [IntegrationBank]..ContractBank T4 with (nolock) on T1.ContractBank = T4.ID
inner join [IntegrationBank]..BoeStatus T5 with (nolock) on T1.[Status] = T5.ID
inner join [UNION_ALL_BASES]..ODSC T6 with (nolock) on T4.BankKey = T6.AbsEntry and **T6.UnionAll_Empresa = T0.UnionALl_Empresa** --I need to do this
where T1.[Status] <> 5
and T2.CompanyDb = **T0.UnionAll_Empresa** --I need to do this
) TBI on (T1.DocEntry = TBI.DocEntry and T1.InstlmntID = TBI.InstallmentID and TBI.DocType = T1.ObjType )
inner join [UNION_ALL_BASES]..OCTG T2 on T0.GroupNum = T2.GroupNum and T0.UnionAll_Empresa = T2.UnionAll_Empresa
inner join [UNION_ALL_BASES]..OSLP T3 on T0.SlpCode = T3.SlpCode and T0.UnionAll_Empresa = T3.UnionAll_Empresa
where not exists (select 1
from [UNION_ALL_BASES]..RIN1 A with (nolock)
inner join [UNION_ALL_BASES]..ORIN B with (nolock) on A.DocEntry = B.DocEntry and A.UnionAll_Empresa = B.UnionAll_Empresa
where A.BaseEntry = T0.DocEntry
and B.SeqCode = ''1'' )
You can user OUTER APPLY
SELECT *
FROM tbl1
OUTER APPLY ( SELECT TOP 1
currency_id,
SUM(taxrate) AS taxrate
FROM tbl2
WHERE wuptr.currency_id = tbl1.currency_id
GROUP BY tbl2.currencyid
)
You don't need a subquery for that:
SELECT item1, *
FROM TableA A
INNER JOIN
TableB B
ON A.item = B.item
AND A.x = B.x;
I can't think of a scenario where you would need to JOIN on a subquery with a filter like that where it wouldn't be equivalent to just reference the field directly in the outer query.
You can reference the outer table in the subquery in the WHERE clause, though:
SELECT <stuff>
FROM Table t
WHERE EXISTS (SELECT 1 from TableB B
WHERE t.id = b.id)
EDIT
For your actual code, just change the JOIN criteria to this:
) TBI on (T1.DocEntry = TBI.DocEntry
and T1.InstlmntID = TBI.InstallmentID
and TBI.DocType = T1.ObjType
AND TBI.CompanyDB = T0.UnionAll_Empresa )
If you want to join on to a subquery and "get a column in real-time"/ reference a column from the main query, then there is a trick to doing this.
You can't access the tables which are outside of the subquery if it's used as an aliased table, in other words, this SQL can never access A:
...
INNER JOIN
(
select *
from TableB B
where A.item = B.item
) on A.x = B.x;
The way to access A would be like this:
SELECT item1, *
FROM TableA A
INNER JOIN TableB on TableB.item = TableA.item and TableB.item in
(
select top 1 B.Item
from TableB B
where A.item = B.item
)
Just ignore the "top 1" piece, I just added that to show that there may a reason for doing a join like this.
So, basically if you want to reference an item from the query in the subquery, just move the subquery to the ON section of a join and use the IN keyword as illustrated above.
You can do this by naming the tables of the main query and the nested query.
For example:
SELECT continent, name, population FROM world x
WHERE population >= ALL
(SELECT population FROM world y
WHERE y.continent=x.continent
AND population>0)
reference: http://sqlzoo.net/wiki/SELECT_within_SELECT_Tutorial
Not sure why people are over-complicating this. #JNK is correct that you can move the predicate into the main query. For completeness, I will demonstrate.
You have two predicates in your subquery that reference T0:
T6.UnionAll_Empresa = T0.UnionAll_Empresa
T2.CompanyDb = T0.UnionAll_Empresa
The first is an INNER JOIN predicate on the table T6, and the second a WHERE clause - these are both "hard" filters, and will filter out results that don't match (unlike a LEFT OUTER JOIN which will simply set reference to that table's values to NULL).
Well, since T6.UnionAll_Empresa and T2.CompanyDb both need to filter against T0.UnionAll_Empresa, then we can simply change the INNER JOIN predicate on T6 to this:
T2.CompanyDb = T6.UnionAll_Empresa
Then, we can remove the WHERE clause in the subquery, and we can add this JOIN predicate to TBI in the main query:
TBI.CompanyDb = T0.UnionAll_Empresa
...making the entire query this:
Select T0.UnionAll_Empresa,<STUFF>
from [UNION_ALL_BASES]..OINV T0 with (nolock)
inner join [UNION_ALL_BASES]..INV6 T1 with (nolock) on t0.DocEntry = t1.DocEntry and t0.UnionAll_Empresa = t1.UnionAll_Empresa
inner join
(
select
t1.CompanyID,
T2.CompanyDb,
t1.OurNumber,
T6.BankCode,
T6.BankName,
T3.[Description] Situation,
T1.[Status],
T5.Descrption nomeStatus,
T1.Origin,
T1.DocEntry,
T1.DocType,
T1.ControlKey,
T1.CardCode,
T4.[Description] ContractBank,
T1.PayMethodCode,
T1.DueDate,
T1.DocDate,
T1.InstallmentID,
T1.InstallmentValue,
T1.Correction,
T1.InterestContractural,
T1.FineContract,
T1.ValueAbatment,
T1.ValueDiscount,
T1.ValueFineLate,
T1.ValueInterestDaysOfLate,
T1.OtherIncreases,
T1.ValueInWords,
T1.ValueDocument,
T1.DigitalLine,
T1.Document
from [IntegrationBank]..BillOfExchange T1 with (nolock)
inner join [InterCompany2]..CompanyHierarchy T2 with (nolock) on T1.CompanyID = T2.ID
left join [IntegrationBank]..BillOfExchangeSituation T3 with (nolock) on T1.Situation = T3.ID
inner join [IntegrationBank]..ContractBank T4 with (nolock) on T1.ContractBank = T4.ID
inner join [IntegrationBank]..BoeStatus T5 with (nolock) on T1.[Status] = T5.ID
inner join [UNION_ALL_BASES]..ODSC T6 with (nolock) on T4.BankKey = T6.AbsEntry and T2.CompanyDb = T6.UnionAll_Empresa
where T1.[Status] <> 5
) TBI on (T1.DocEntry = TBI.DocEntry and T1.InstlmntID = TBI.InstallmentID and TBI.DocType = T1.ObjType and TBI.CompanyDb = T0.UnionAll_Empresa)
inner join [UNION_ALL_BASES]..OCTG T2 on T0.GroupNum = T2.GroupNum and T0.UnionAll_Empresa = T2.UnionAll_Empresa
inner join [UNION_ALL_BASES]..OSLP T3 on T0.SlpCode = T3.SlpCode and T0.UnionAll_Empresa = T3.UnionAll_Empresa
where not exists (
select 1
from [UNION_ALL_BASES]..RIN1 A with (nolock)
inner join [UNION_ALL_BASES]..ORIN B with (nolock) on A.DocEntry = B.DocEntry and A.UnionAll_Empresa = B.UnionAll_Empresa
where A.BaseEntry = T0.DocEntry
and B.SeqCode = ''1''
)
This is entirely equivalent to what you have, and removes any reference to T0 from your subquery.
You can also use WITH
http://msdn.microsoft.com/en-us/library/ms175972.aspx

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.