Conditional Join SQL - sql

I want to be able to inner join two tables based on the value of a column I'm selecting.
My Query:
SELECT varA, varB, MAX(varC) varC
FROM table1
INNER JOIN table2 ON varB = table2.varB
INNER JOIN #tempTable ON varA = table1.column
INNER JOIN table3 ON varC = table3.column AND table3.column2 = 1 -- **IF NOT varA = 100**
INNER JOIN table4 ON varC = table4.column **-- IF varA = 100**
LEFT OUTER JOIN table5 ON table2.column = table5.column AND table5.column2 = 1 AND table5.column3 = 4
GROUP BY varB, varA
So, in short INNER JOIN on table4 if value of column(varA) is not 100 else INNER JOIN on table3

I think this will get the result you're after:
LEFT JOIN table3 ON varC = table3.column AND table3.column2 = 1 AND varA <> 100 -- **IF NOT varA = 100**
LEFT JOIN table4 ON varC = table4.column AND varA = 100 **-- IF varA = 100**
...
WHERE (Table3.Column IS NOT NULL OR Table4.Column IS NOT NULL)
Basically allows a join to either table, but only return rows where one of those joins found a record. If you want to return the actual columns from the table as part of the select then you could use an ISNULL:
SELECT ISNULL(Table3.Column, Table4.Column) AS Column
EDIT: I should have added that you can't conditionally join to tables unless you want to use dynamic SQL. You can either join to the table or not. What I outlined above lets you do the join to both tables and then check that one of them did join (which is basically what an Inner Join does).

So, in short INNER JOIN on table3 if varA is not 100 else INNER JOIN on table4.
That cannot be effectively done in one query. At execution time, the database must decide what joins to perform on a whole-table basis, not a row-by-row basis. If you attempt to do what you propose, what you will get, at best, is that the database will join on both table3 and table4. At worst, the joins will be Cartesian (unrestricted "all rows * all rows" joins).
So you only have these two options:
Join to both tables, and select on a row-by-row basis whether to produce data from table3 or table4 for that row.
Split the query into two queries joined by UNION. One of the queries joins with table3, the other joins with table4. You use the condition to control which rows are produced by the first query and which by the second one; i.e., the subquery that joins with table3 has varA != 100 in the WHERE clause, and the subquery that joins with table4 has varA = 100.

Your question isn't quite clear and if this doesn't work please provide more info but I think this is your answer.
You can place a CASE statement in the join.
Updated, try this.
INNER JOIN table4 ON (CASE WHEN varA != 100 THEN 1 ELSE 0 END) = 1 AND tablekey=table4key
INNER JOIN table3 ON (CASE WHEN varA = 100 THEN 1 ELSE 0 END) = 0 AND tablekey=table3key

Related

SQL Full Outer Join : Whats the difference in these queries?

Lets suppose I have a full outer join query written in these styles:
SELECT * FROM Table_A
FULL OUTER JOIN Table_B ON (Table_A.Col1 = Table_B.Col1 AND Table_B.iscurrent=1)
Versus
SELECT * FROM Table_A
FULL OUTER JOIN (Select * FROM Table_B Where iscurrent=1) AS Table_B
ON (Table_A.Col1 = Table_B.Col1)
Both are producing different results in my database (Azure SQL DB).
How come?
Why are they returning different results? Because they are different queries. FULL OUTER JOIN is very tricky. Let me explain.
The result set from the first query has rows from all the rows in both tables, even those where Table_B.iscurrent <> 1. If this is not true, then the corresponding columns will be NULL, but the row will be there.
The result set from the second query will have no rows were Table_B.iscurrent <> 1. These are filtered out before the FULL OUTER JOIN, so they are not among the rows being counted.
In general, I find that FULL OUTER JOIN is very rarely needed. I do use it, but quite rarely. Typically LEFT JOIN or UNION ALL does what I really want.
On the second only rows with Where Table_B.iscurrent = 1 are included.
In the first you have all the rows in Table_B but they just don't connect to Table_A if iscurrent <> 1.
SELECT *
FROM Table_A
FULL OUTER JOIN Table_B
ON Table_A.Col1 = Table_B.Col1
AND Table_B.iscurrent = 1
SELECT *
FROM Table_A
FULL OUTER JOIN ( Select *
FROM Table_B
Where iscurrent = 1
) AS Table_B
ON Table_A.Col1 = Table_B.Col1

How to use SQL Joins and Selects to get results from a third table that matches the first two?

I have a Join statement on two tables(Table 1 and 2), which returns the City and State. I have another table(Table 3) which contains columns like Name, City, State, Country. I want to fetch all the rows from Table 3 whose City and State Columns matches with the rows of the Join result.
Select * from 3rdTable where City='' AND State='';
Result from Join is like
- City | State
- A | B
- C | D
- E | F
Example Result if only 1 row of the 3rd table matches
- C | D
How can this be done?
You can use the joined table as a sub table in 3rdTable to create a where clause as follows;
select *
from 3rdTable
where City+'|'+State= (select a.City+'|'+b.State
from a
inner join b
on a.x=b.y)
Buy concatenating the fields, you can create a single equality to the joined subquery
Be sure about the joins, we have inner join, Left join, right join and outer join; maybe knowing the difference can help you to answer your question.
and also the code is not clear :)
Just join in the 3rd table...
IF we assume table1 has both city and state in it...
SELECT A.City, A.State
FROM Table1 A
INNER JOIN table2 B
on A.PK = B.A_FK
INNER JOIN table3 C
on A.City = C.City
and A.State = C.State
This is the nature of an inner join: Include all rows from all tables where the joined data matches.
If you use an OUTER join (left, right, full outer) then you get all records from one table and only those that match in the others, or full outer all records from all tables aligned where they match.
SELECT *
FROM table3 t3
INNER JOIN (SELECT city,
state
FROM table1 T1
JOIN table2 t2
ON t1.id = t2.id) a1
ON t3.city = a1.city
AND t3.state = a1.state
I think this could help you:
SELECT T3.*
FROM
table_1_2_join T12 /* replace this placeholder table with the select statement that joins your 2 tables */
JOIN table_3 T3 ON T3.City = T12.city AND T3.state = T12.state
Let me know if you need more details.

I cannot get this LEFT JOIN to work (I don't understand joins)

These queries both get results:
SELECT * FROM Table1 WHERE Criteria = '5'
SELECT * FROM Table1 WHERE Criteria = '3'
This query gets results:
SELECT *
FROM Table1 p, Table2 m
WHERE p.UID = m.ID
AND Criteria = '5'
This query does not:
SELECT *
FROM Table1 p, Table2 m
WHERE p.UID = m.ID
AND Criteria = '3'
I am trying to convert these to a proper join which returns results even if there are no records in the right table.
I have tried the following
SELECT *
FROM Table1 p LEFT JOIN Table2 m ON p.UID = m.ID
WHERE p.Criteria = '3'
AND m.OtherCriteria = 'Moron'
--0 results
My limited understanding was that LEFT join is what I needed. I want data from the left table even if there is no data in the right table that matches. Since this didn't work I also tried right join, left outer join, right outer join and full join. None returned results.
What am I missing?
This is too long for a comment. Your query:
SELECT *
FROM Table1 p LEFT JOIN
Table2 m
ON p.UID = m.ID AND p.Criteria = '3';
Should be returning a row for all rows in table1. If there is no match, then the values will be NULL for table2. This is easily demonstrated: Here is a MySQL example on SQL Fiddle. Because this is standard behavior, it should work on almost any database.
Note that this query is quite different from this one:
SELECT *
FROM Table1 p LEFT JOIN
Table2 m
ON p.UID = m.ID
WHERE p.Criteria = '3';
This query returns no rows, because no rows match the WHERE clause. The filtering happens (conceptually) after the LEFT JOIN.
I changed the code in the SQL Fiddle slightly, so that query is:
select *
from (select 5 as criteria, 1 as id union all
select 6, 1 union all
select 7, 2
) table1 left join
(select 1 as id, 'x' as x
) table2
on table1.id = table2.id and criteria = 3;
As a note: you should always use explicit join syntax. Simple rule: Never use commas in the FROM clause.
If your database is returning no rows, then it is behaving in a non-standard manner or your interface has decided to filter the rows for some reason.

Old SQL? multiple tables after FROM

I'm trying to rewrite the following query which was generated in some part by Impromptu. For some reason I cannot get my head around the multiple tables after the FROM and the nest of joins that follows. I have always used a "master" table then joined anything I would need after that. i.e select from, left join (table) on x=x left join (table) on x=x and so on.
I'm having a difficult time with the parenths etc... in this. What would it look like written in "normal" query style? Thanks so much in advance!
select
T6."dateofservice"
, getdate(), -20000 - (1 - convert(float(53),-2) / abs(-2)) / 2
, T1."pgrp_specialty"
, T1."pgrp_prov_combo"
, T2."patsex"
, T3."restricted"
, T2."patdob"
, T2."patdecdate"
, T2."acctno"
, T2."patno"
from
"acctdemo_t" T3, "transaction_t" T5,
("patdemo_t" T2
LEFT OUTER JOIN ("provcode_t" T8
LEFT OUTER JOIN "provalt_t" T1 on T8."px" = T1."accesspractice" and T8."provcode" = T1."accessprovidercode") on T2."provcode" = T8."provcode")
LEFT OUTER JOIN "insset_t" T4 on T2."acctno" = T4."acctno" and T2."patno" = T4."patno", "charge_t" T6
LEFT OUTER JOIN "poscode_t" T7 on T6."poscode" = T7."poscode"
where
T2."patsex" <> 'U'
and T7."posid" = '3'
and T6."correction" = 'N'
and T5."txtype" = 'C'
and (T4."defaultset" = 'Y' or
(T4."inssetno" = 0 or T4."inssetno" is null)
and T4."defaultset" is null)
and T6."chgno" = T5."chgno"
and T2."patno" = T6."patno"
and T2."acctno" = T6."acctno"
and T2."acctno" = T3."acctno"
SQL written with multiple tables, separated by comma is implied INNER JOIN, with the where clause serving as the join clause. For example,
select * from table1 a, table2 b
where a.id = b.id
is the same as:
select * from table1 a inner join table2 b on a.id = b.id
So, in your case, this part:
from "acctdemo_t" T3
, "transaction_t" T5
is implying inner join between acctdemo_t and transaction_t.
And - the third part of this:
("patdemo_t" T2 LEFT OUTER JOIN
("provcode_t" T8 LEFT OUTER JOIN "provalt_t" T1 on T8."px" = T1."accesspractice" and T8."provcode" = T1."accessprovidercode")
on T2."provcode" = T8."provcode")
Is actually a tableset being created on the fly with its own clauses, and is basically acting as a table in this join. Also being joined with Inner join, since its added with a comma.
I believe this can definitely written to be more readable, and the inline tableset being created isn't going to be good for performance, but that totally depends on the number of records you have.

Left Outer join and an additional where clause

I have a join on two tables defined as a left outer join so that all records are returned from the left hand table even if they don't have a record in the right hand table. However I also need to include a where clause on a field from the right-hand table, but.... I still want a row from the left-hand table to be returned for each record in the left-hand table even if the condition in the where clause isn't met. Is there a way of doing this?
Yes, put the condition (called a predicate) in the join conditions
Select [stuff]
From TableA a
Left Join TableB b
On b.Pk = a.Pk
-- [Put your condition here, like this]
And b.Column = somevalue
The reason this works is because the query processor applies conditions in a where clause after all joins are completed, and the final result set has been constructed. So, at that point, a column from the a table on the outer side of a join that has null in a a column you have established a predicate on will be excluded.
Predicates in a join clause are applied before the two result sets are "joined". At this point all the rows on both sides of the join are still there, so the predicate is effective.
You just need to put the predicate into the JOIN condition. Putting it into the WHERE clause would effectively convert your query to an inner join.
For Example:
...
From a
Left Join b on a.id = b.id and b.condition = 'x'
You can use
WHERE (right_table.column=value OR right_table.column IS NULL)
This will return all rows from table 1 and table 2, but only where table 1 does not have a corresponding row in table 2 or the corresponding row in table 2 matches your criteria.
SELECT x.fieldA, y.fieldB
FROM x
LEFT OUTER JOIN (select fieldb, fieldc from Y where condition = some_condition)
ON x.fieldc = y.fieldc
select *
from table1 t1
left outer join table2 t2 on t1.id = t2.id
where t1.some_field = nvl(t2.some_field, t1.some_field)
UPD: errr... no. this way:
select *
from table1 t1
left outer join table2 t2 on t1.id = t2.id
where some_required_value = nvl(t2.some_field, some_required_value)
nvl is an Oracle syntax which replaces first argument with second in case it is null (which is common for outer joins). You can use ifnull or coalesce for other databases.
Thus, you compare t2.some_field with your search criteria if it has met join predicate, but if it has not, then you just return row from table1, because some_required_value compared to itself will always be true (unless it is null, however - null = null yields null, neither true not false.