More than two table using joins - sql

MainTable
ID Column1 TableA.fK TableB.fk
1 some-value 1 null
2 some-value 1 1
3 some-value null 2
TableA
TableA.pk Column1
1 some-value
TableB
TableB.pk Column1
1 some-value
2 some-value
Select Main.ID,Main.Column1 ,A.Column1,B.Column1
FROM MainTable main
LEFT JOIN
Table A
ON Main.TableA.fk = A.TableA.pk
LEFT JOIN
TableB b
ON Main.TableB.fk =B.TableB.fk
WHERE Main.ID =1
Means
The Result is
ID Column1 A.Column1 B.Column1
1 some-value some-value null
Expecting Output
ID column1 A.Column1
1 some-value some-value
should not display B.column1
when tableA foreign key value has not null, it should get all details from TableA if above SELECT query used here
im using RDBMS Microsoft Sql Server 2008

Just don't put this column into the SELECT list:
SELECT Main.ID, A.Column1
FROM MainTable main
LEFT JOIN
Table A
ON Main.TableA.fk = A.TableA.pk
LEFT JOIN
TableB b
ON Main.TableB.fk = B.TableB.fk
WHERE Main.ID = 1

Remove B.Column1 from your query
Select Main.ID,A.Column1 FROM MainTable main LEFT JOIN Table A ON Main.TableA.fk=A.TableA.pk LEFT JOIN TableB b ON Main.TableB.fk =B.TableB.fk WHERE Main.ID =1

I don't understand the problem here. If you don't want it to display B.Column1, take B.Column1 out of your Select statement.
You now have
Select Main.ID, A.Column1, B.Column1
Change it to
Select Main.ID, A.Column1
Based on your comments below, it seems like you're looking for Coalesce or IsNull, depending on which DBMS you're using (which you didn't tell us in your question either).
Something like this should work:
SELECT
Main.ID, Coalesce(A.Column1, B.Column1) as Column1
FROM
MainTable main
LEFT JOIN
Table A
ON
Main.TableA.fk = A.TableA.pk
LEFT JOIN
TableB b
ON
Main.TableB.fk = B.TableB.fk
WHERE
Main.ID = 1

Related

Join two table with Multiple cases in ON condition

I have two tables A and B and I have to perform left join on that with multiple cases in on condition.
Is there any efficient way of doing this in big query or SQL.
select * from table_A A
left join table_B B
where
[some condition OR some condition]
on
case1
A.column1 =B.column1
and A.column2= B.column2
and A.column3= B.column3
and A.column4= B.column4
and A.column5= B.column5
OR case2
A.column1 =B.column1
and A.column3= B.column3
and A.column4= B.column4
and A.column5= B.column5
OR case3
A.column1 =B.column1
and A.column2= B.column2
and A.column4= B.column4
OR case4
A.column1 =B.column1
and A.column3= B.column3
and A.column5= B.column5
Here my main motive is that for one row if my case1 matches than it will not go into other cases. Likewise it will work if first is not matches then it will check second, then third and it will get best possible one match.
Here the cases will help that to get 100% of join between A and B table.
In first cases we are checking all 5 fields of both table, but if some of the field are null than it will check other case and likewise it should work.
If I understand correctly, the general approach in SQL is multiple left joins:
select a.*, coalesce(b1.col, b2.col, b3.col, b4.col) as col
from table_A A left join
table_B B1
on A.column1 = B1.column1 and
A.column2 = B1.column2 and
A.column3 = B1.column3 and
A.column4 = B1.column4 and
A.column5 = B1.column5 left join
table_b B2
on B1.column1 is null and
A.column1 = B2.column1 and
A.column3 = B2.column3 and
A.column4 = B2.column4 and
A.column5 = B2.column5 left join
table_b B3
on B2.column1 is null and
A.column1 = B3.column1 and
A.column2 = B3.column2 and
A.column3 = B3.column3 left join
table_b B4
on B3.column1 is null and
A.column2 = B4.column2 and
A.column4 = B4.column4
You want to get the "best" matching B rows. I.e. if there are rows matching case 1, you want to stick with these, but if there are none, then you want to try with case 2, etc.
What you can do is combine the conditions, so as to join all possible matches first. Then look at the matches and dismiss all except the best ones. Ranking can be done with RANK.
select *
from
(
select
*,
rank() over (partition by A.id
order by
case when A.column2 = B.column2
and A.column3 = B.column3
and A.column4 = B.column4
and A.column5 = B.column5 then 1
when A.column3 = B.column3
and A.column4 = B.column4
and A.column5 = B.column5 then 2
when A.column2 = B.column2
and A.column4 = B.column4 then 3
else 4
end) as rnk
from table_A A
left join table_B B
on A.column1 = B.column1
and
(
(A.column2 = B.column2 and A.column4 = B.column4)
or
(A.column3 = B.column3 and A.column5 = B.column5)
)
where [some condition OR some condition]
) ranked
where rnk = 1;
(My query assumes some ID in table_A. If your table doesn't have a unique ID, use whatever column(s) uniquely identify a row in the table.)
The solution can be to use a temporary data storage (temp table, cursors, or whatever) and use a parametrized loop to feed it. The problem that you have is that in pure SQL you don't have loops. You have to use the scripting languages of bigQuery, give a look here https://cloud.google.com/bigquery/docs/reference/standard-sql/scripting
Below two options I see - both for BigQuery Standard SQL (Thank you to #Thorsten-Kettner for helping in understanding OP's logic/requirements)
Option 1 - separate joins for each case; then combine all and finally pick the winner for each record in A
#standardSQL
SELECT * EXCEPT(priority, identity)
FROM (
SELECT AS VALUE ARRAY_AGG(t ORDER BY priority LIMIT 1)[OFFSET(0)]
FROM (
SELECT *, 1 priority, FORMAT('%t', A) identity
FROM table_A A LEFT JOIN table_B B
USING(column1,column2,column3,column4,column5) -- Case 1
WHERE [SOME condition OR SOME condition]
UNION ALL
SELECT *, 2 priority, FORMAT('%t', A) identity
FROM table_A A LEFT JOIN table_B B
USING(column1,column3,column4,column5) -- Case 2
WHERE [SOME condition OR SOME condition]
UNION ALL
SELECT *, 3 priority, FORMAT('%t', A) identity
FROM table_A A LEFT JOIN table_B B
USING(column1,column2,column4) -- Case 3
WHERE [SOME condition OR SOME condition]
UNION ALL
SELECT *, 4 priority, FORMAT('%t', A) identity
FROM table_A A LEFT JOIN table_B B
USING(column1,column3,column5) -- Case 4
WHERE [SOME condition OR SOME condition]
) t
GROUP BY identity
)
Option 1 - just pick all potential candidates in one query with on fly calculating which case the entry belong to and finally pick the winner for each row in A
#standardSQL
SELECT * EXCEPT(priority, identity)
FROM (
SELECT SELECT AS VALUE ARRAY_AGG(t ORDER BY priority LIMIT 1)[OFFSET(0)]
FROM (
SELECT A.*,
B.* EXCEPT(column1,column2,column3,column4,column5),
FORMAT('%t', A) identity
CASE
WHEN (A.column1,A.column2,A.column3,A.column4,A.column5) = (B.column1,B.column2,B.column3,B.column4,B.column5) THEN 1
WHEN (A.column1,A.column3,A.column4,A.column5) = (B.column1,B.column3,B.column4,B.column5) THEN 2
WHEN (A.column1,A.column2,A.column4) = (B.column1,B.column2,B.column4) THEN 3
WHEN (A.column1,A.column3,A.column5) = (B.column1,B.column3,B.column5) THEN 4
ELSE 5
END AS priority,
FROM table_A A LEFT JOIN table_B B
ON A.column1 = B.column1
OR A.column2 = B.column2
OR A.column3 = B.column3
OR A.column4 = B.column4
OR A.column5 = B.column5
WHERE [SOME condition OR SOME condition]
) t
WHERE priority < 5
GROUP BY identity
)
Note: above versions have similarity and different at the same time - it is matter of preferences to pick one vs another. Also wanted to note - above is not tested and just written on-fly so might need additional tunning - but most likely not :o)

How can I construct 2 columns from the same data and compute ratio?

I have a database with many tables and I would like to create two columns from the same data with different filtering for each. Specifically, I have the following SQL query:
select count(*), A.Column1
from Table1 as A
join Table2 as B
on A.Column2 = B.Column2
where B.Column3 in (
select C.Column3
from Table3 as C
where (C.Column4=9 or C.Column4=4))
group by A.Column1
This creates a table with 2 columns. I would like a 3rd column (another count(*)) which only differs in that there will be a 3rd qualifier in the where clause. I would also like to create a column which computes the ratio of these 2 count columns.
Can this be done in SQL or must I get the data into R or Python and do the calculations there?
If you want a ratio of the two columns, then divide:
select count(*), A.Column1,
avg(case when ? then 1.0 else 0 end) as ratio
from Table1 A join
Table2 B
on A.Column2 = B.Column2
where B.Column3 in (select C.Column3
from Table3 C
where (C.Column4 in (4, 9)
)
group by A.Column1;
The ? is for the condition that you care about.
Change the case when to match the criteria on your second filter.
select count(case when C.Column4 = 9 or C.Column4 = 4 then 1 else null end) as Count1
, count(case when C.Column4 = 9 or C.Column4 = 22 then 1 else null end) as Count2
, A.Column1
from Table1 as A
join Table2 as B
on A.Column2 = B.Column2
where B.Column3 in (
select C.Column3
from Table3 as C
group by A.Column1

XOR JOIN in SQL

I have the following tables
Table A
ID "Other Columns"
1
2
3
Table B
ID "Other Columns"
3
4
5
What is the efficient way to return the below result?
Result
ID "Other Columns"
1
2
4
5
A full outer join should work, and only go through each table once. They can be tricky, so test carefully!
SELECT
isnull(A.ID, B.ID) ID
,"Other columns" -- Handle nulls properly!
from TableA A
full outer joing TableB B
on B.ID = A.ID
where not (A.ID is not null
and B.ID is not null)
You want to use left and right join and union them
Select TableA.ID as 'ID','Other Colums'
FROM TableA Left join TableB
ON TableA.ID=TableB.ID
WHERE TableB.ID IS NULL
UNION
Select TableB.ID as 'ID','Other Colums'
FROM TableA Right join TableB
ON TableA.ID=TableB.ID
WHERE TableA.ID IS NULL
You can try like this
SELECT
COALESCE(a.id, b.id),
OtherColumns
FROM #tablea a
FULL JOIN #tableb b
ON a.id = b.id
WHERE a.id IS NULL
OR b.id IS NULL
You can do this with a UNION ALL using a LEFT JOIN to determine if the ID is not in the other table. Keep in mind that the column count and datatypes between the two tables must match up:
Select A.Id, A.OtherColumns
From TableA A
Left Join TableB B On A.Id = B.Id
Where B.Id Is Null
Union All
Select B.Id, B.OtherColumns
From TableB B
Left Join TableA A On A.Id = B.Id
Where A.Id Is Null
Not quite sure what you need with the "Other columns", but you could use EXCEPT:
Select ID from TableA
EXCEPT
Select ID from TableB
If you need Other columns from TableA you could use:
Select ID, OtherColumn1, OtherColumn2 from TableA
where ID not in (select ID from TableB)
(as long as ID cannot be null in TableB)
I broke down each part to be clearer!
select *
into #temp
from
TabA Full outer join TabB
on TabA.ColNameA = TabB.ColNameB
select *
into #temp2
from #temp
where (ColNameA is Null Or ColNameB is null)
select ColNameA from #temp2
where ColNameA Is not null
union
select ColNameB from #temp2
where ColNameB Is not null

What is the T-SQL Syntax for If This or This then That else Do Nothing?

I am trying to make a condition where for a certain ID, when either of two values from two different tables are greater than a number, then I will display a row with both values. Otherwise, I don't want to display any new row. What is the correct syntax for this?
if(select
a.Column1 > 2 or
b.Column2 > 2
from
Table1 a join Table2 b on a.ID = b.ID)
begin
select
a.Column1,
b.Column2
from
Table1 a join Table2 b on a.ID = b.ID)
end
else
begin
Don't Select
end
You just need to add it as a where condition. If your where condition fails for a given row, that row wouldn't be selected.
select
a.Column1,
b.Column2
from
Table1 a join Table2 b on a.ID = b.ID
where a.column1 > 2 or b.column2 > 2
#vkp's answer is probably what you want, but the literal translation of the query you have written -- without using control-flow statements -- is this:
select
a.Column1,
b.Column2
from
Table1 a join Table2 b on a.ID = b.ID
where exists (select 1 from Table1 c join Table2 d on c.ID = d.ID where c.Column1 > 2 or d.Column2 > 2);
This will either return nothing at all if one of records in the join doesn't have Table1.Column1 > 2 or Table2.Column2 > 2, or it will return all records.

Using a Oracle subselect to replace a CASE statement

Hy guys,
can anybody please help me with a subquery in Oracle database 10g? I need to extract the values for a column in the first table as value of another column in the second table.
I currently use this statement:
SELECT
CASE WHEN A.column1 = 'A' THEN 'aaa'
WHEN A.column1 = 'B' THEN 'bbb'
.......
WHEN A.column1 = 'X' THEN 'xxx'
ELSE 'bad' END AS COLUMN1, A.*
FROM TRANSACTION_TABLE A, CATEGORY_TABLE B
WHERE A.column1 IS NOT NULL
AND A.column1 <> ' '
This is not an elegant approach, so I'm trying to use a subselect from CATEGORY_TABLE B like the following:
SELECT A.column1, A.*
FROM TRANSACTION_TABLE A, CATEGORY_TABLE B
WHERE A.column1 IS NOT NULL
AND A.column1 = B.column_b_1
AND A.column1 <> ' '
AND A.column1 IN (SELECT B.column_b_1_descr FROM CATEGORY_TABLE B
WHERE B.FIELDNAME = 'column1' AND A.column1 = B.column_b_1)
So, I cannot get any results by using the subquery and don't want to continue using the CASE against many conditions, just want to replace the A.column1 values with the descriptive values from B.column_b_1_descr , as they're easier to read.
I would appreciate any feedback.
Thanks
Unless I'm misunderstanding your question...
CATEGORY_TABLE:
name | value
A aaa
B bbb
C ccc
...
SELECT B.value AS COLUMN1, A.\*
FROM TRANSACTION\_TABLE A, CATEGORY\_TABLE B
WHERE A.column1 = B.name
or
SELECT t2.value as COLUMN1, t1.\*
FROM TRANSACTION\_TABLE t1
INNER JOIN CATEGORY\_TABLE t2 ON t1.column1 = t2.name;
The where clause isn't needed, since an inner join automatically excludes rows with null values or no matches.