How to reduce number of joins? - sql

I have to left join two tables where from right table I need some columns On a join condition of three columns, and some columns on join condition of two similar but one different column (again 3 columns) and some columns on join condition of one column (which is one of the non-matching columns in previous joins).
Let me explain by example
Table A has columns a1, a2, a3, a4, a5
Table B has columns b1, b2, b3, b4, b5, b6, b7
Now I need
a1,
a2,
a3,a4,
b1 when a2=b2, a3=b3, a4=b4,
b6 when a2=b5, a3=b3, a4=b4,
b7 when a2=b2
Now How can I achieve this without joining the tables multiple times, Or as less times as possible. With CASE WHEN THEN structure or anything else. The queries are for Hive but most of sql features are supported. Hive has different optimization techniques but sql guys are welcome.
Thanks in advance for your effort.

I'm pretty sure hive supports conditional aggregation. If I'm understanding your question correctly, you should be able to use that with a cross join:
select a1, a2, a3, a4,
max(case when a2 = b2 and a3 = b3 and a4 = b4 then b1 end) b1,
max(case when a2 = b5 and a3 = b3 and a4 = b4 then b6 end) b6,
max(case when a2 = b2 then b7 end) b7
from a cross join b
group by a1, a2, a3, a4

You want to do multiple joins:
select a.a1, a.a2, a.a3, a.a4, b1.b1, b2.b6, and b3.b7
from a join
b b1
on a.a2 = b1.b2 and a.a3 = b1.b3 and a.a4 = b1.b4 join
b b2
on a.a2 = b2.b5 and a.a3 = b2.b3 and a.a4 = b2.b4 join
b b3
on a.a2 = b.b2;
You may need left join if some conditions do not match.

Related

Select entries that have non repeating values on a specific column (although other columns may have repeating or non repeating values) (SQL)

Let's say I have the following table:
A
B
C
D
a1
b1
c1
d1
a1
b1
c1
d2
a2
b2
c3
d3
a2
b2
c4
d3
I want to filter and see all four columns for entries that have the same value con column A but different on column C, so I get only this as a result:
A
B
C
D
a2
b2
c3
d3
a2
b2
c4
d3
I don't really care if values con columns B and D are the same or different, although I would like to have them in my table to do further analysis later.
Using the DISTINCT statement would give me all the columns as a result, as they all are different in some column, so that doesn't work for me.
I read some questions (like this one) and the answers recommended using the row_number() over(partition by...) clause, although the use they gave it doesn't quite fit my problem (I think), as it would also return the first row with a repeating value on column C.
Any ideas how this could be done?
You can use exists:
select t.*
from t
where exists (select 1
from t t2
where t2.a = t.a and t2.c <> t.c
)
order by t.a;
You could use a self join
select t1.*
from t t1
join t t2 on t1.a=t2.a and t1.c<>t2.c

Update values from one table in another

I have tables A,B and C. I need to select certain values from all rows in Table A and then for every row in A, I need to update values in Table B and Table C.
Pseudo Code would look like this:
SELECT A1, A2, A3, A4 FROM Table A
UPDATE Table B SET B2=A2, B3=A3, B4=A4 WHERE B1 = A1;
UPDATE Table C SET C2=A2, C3=A3, C4=A4 WHERE C1 = A1;
How can I achieve this?
In Oracle, you would use two update statements:
update b
set (b2, b3, b4) = (select a2, a3, a4 from a where a.a1 = b.b1);
update c
set (c2, c3, c4) = (select a2, a3, a4 from a where a.a1 = c.b1);
You need two update statements. You could use an inline view:
update (
select a.a2, a.a3, a.a4 , b.b2, b.b3, b.b4
from a
inner join b on b.b1 = a.a1
) u
set u.b2 = u.a2, u.b3 = u.a3, u.b4 = u.a4
The upside is that this only updates matching rows - while, using the correlated subquery technique, you need to repeat the subquery in the where clause.
Another neat syntax that does what you want in Oracle is merge:
merge into b
using a on (a.a1 = b.a1)
when matched then update set b.b2 = a.a2, b.b3 = a.a3, b.b4 = a.a4;

Finding Permutations of columns in SQL

I have a reference data table having columns as codes and values.
For e.g. there are three code types viz. A, B, C.
The table is as below:
Code Value
---------------------
A1 a_one
A2 a_two
B1 b_one
B2 b_two
B3 b_three
C1 c_one
C2 c_two
C3 c_three
C4 c_four
---------------------
I have a requirement where the input will be code types and output should be all permutations between the input code types.
For e.g. if the input code types are A and C, the output of my sql should be:
col_1 col_2
---------------------
A1 C1
A1 C2
A1 C3
A1 C4
A2 C1
A2 C2
A2 C3
A2 C4
---------------------
Similarly if the input code types is A, B, C, the output of the sql will have three columns with all the permutations between A, B, C viz. A1 B1 C1 to A2 B3 C4.
I have no idea how to start on this. So any hints will be useful.
Thanks for reading!
If I understand your question correctly, this is one of those rare cases where a CROSS JOIN is actually what you want. A CROSS JOIN will give you the Cartesian product of two sets, which means all possible combinations between the values in those sets.
Example:
Table A with column 1 contains values 'a' and 'b'
Table B with column 2 contains values 'c' and 'd'
The following CROSS JOIN query (note there is no 'join condition' specified, on purpose):
SELECT *
FROM A
CROSS JOIN B
will return the following result:
1 2
--------
a c
a d
b c
b d
I created an SQL Fiddle to show you a possible solution. You can tweak it a bit to see if this is what you need. (Note it's an Oracle fiddle, as there is no DB2 option.)

SQL: self join using each rows only once [duplicate]

This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
combinations (not permutations) from cross join in sql
I've currently got a table with the following records:
A1
A2
A3
B1
B2
C1
C2
Where the same letter denotes some criteria in common (e.g. a common value for the column 'letter'). I do a self join on the criteria as follows:
SELECT mytable.*, self.* FROM mytable INNER JOIN mytable AS self
ON (mytable.letter = self.letter and mytable.number != self.number);
This join gives something like the following:
A1 A2
A2 A1
A1 A3
A3 A1
A2 A3
A3 A2
B1 B2
B2 B1
C1 C2
C2 C1
However, I only want to include each pair once (a combination instead of a permutation).
How would I get the following:
A1 A2
A1 A3
A2 A3
B1 B2
C1 C2
Changing the JOIN condition slightly will achieve what you want..
Instead of:
ON (mytable.letter = self.letter and mytable.number != self.number)
use
ON (mytable.letter = self.letter and mytable.number > self.number)
This will only include combinations where self.number is greater than mytable.number which in effect restricts the results to one valid ordering of each combination...

DB Sorting Challenge

I have a table as follows,
A A
B B1
A A1
B B
A A2
B B3
A A3
B B2
My result set should be,
A A
A A1
A A2
A A3
B B
B B1
B B2
B B3
Note: A, A1 are all GUIDs.
I have tried quite a few tricks. Please help me solve this problem.
I'm assuming that the spaces indicate separate columns.
select * from [Table] order by [column1], [column2]
If each line is a string then doing an order by [column1] should be sufficient.
Maybe I am missing something, but I figured this would be:
ORDER BY Column1, Column2
Perhaps you could explain this further?