Can you use a Select statement in an joins on clause? - sql

I am trying to use a sub query to pick an column to join on to, is this even possible:
if let's say table b has a value that = the column name of table a?
Please note the below example does specify the table_b.Column_A however this is to make my question clearer and less cluttered. The where condition will always return an single value/record.
EDIT: I am trying to basically create an dynamic on clause if that makes any sense.
Further more the only relationship the tables have is that Table_b contains Table_a's columns as values.
SELECT *
FROM table_a a
INNER JOIN table_b b
ON a.(select column1 FROM table_b WHERE Column1 ='Column_A') = b.Column_A

Is this what you want?
SELECT *
FROM table_a a INNER JOIN
table_b b
ON (b.Column1 = 'Column_A' AND a.column1 = b.column_A) OR
(b.Column1 = 'Column_B' AND a.column1 = b.column_B) OR
(b.Column1 = 'Column_C' AND a.column1 = b.column_C)
You would have to list out all the columns directly. Also, JOINs with ORs generally have very poor performance.
You can express this more concisely using APPLY:
SELECT *
FROM table_b b CROSS APPLY
(SELECT 'Column_A' as colname, b.Column_A as colval FROM DUAL UNION ALL
SELECT 'Column_B', b.Column_B FROM DUAL UNION ALL
SELECT 'Column_C', b.Column_C FROM DUAL
) v JOIN
table_a a
ON a.column1 = v.colval
WHERE v.colname = b.Column1
Note that this version works in Oracle 12C+.

You can't use the select statement in way you are trying but looking to you code you could use and condition eg:
SELECT *
FROM table_a a
INNER JOIN table_b b ON a.column1 = b.Column_A
and b.Column1 ='Column_A'
Otherwise if you want build dynamically the query code you should build server side a string then using this string as a command

Related

Hive join tables and keep only 1 column

I have below table join and noticed that Hive keeps two copies of the pk column - one from table b and one from table c. Is there a way to keep only 1 of those columns?
I can always replace select * with exact select column1, column2 etc but that wont be too efficient
with a as (
select
*
from table1 b left join table2 c
on b.pk = c.pk
)
select
*
from a;
;
#update 1
is it possible to alias many columns?
for example the below line works
select b.pk as duplicate_pk
but is there a way to do something like
select b.* as table2 to add text table2 before all the columns of the table b?
Not sure if you already tried this but you can choose what to select using either
b.* to select cols of only table1
c.* to select cols of only table2
Example:
with a as (
select
b.*
from table1 b left join table2 c
on b.pk = c.pk
)
select
*
from a;

Query from Join 2 table subqueries without where or Query from joined table with where is fasster

Assume I have 2 tables A (ID, col1, col2) and B (ID, col1, col2).
Is it better to write
SELECT *
FROM
(SELECT *
FROM A
WHERE col1 = 1) A
JOIN
(SELECT *
FROM B
WHERE col2 = 2) B ON A.ID = B.ID
or rather:
SELECT *
FROM A
JOIN B ON A.ID = B.ID
WHERE A.col1 = 1
AND B.col2 = 2
Yes. It's better to use joins.
Joining data with WHERE clause does NOT allow you to grab data like LEFT|RIGHT JOIN does. WHERE clause allows you to grab data in the way in which INNER JOIN does.
For further details, please see: Visual representation of SQL Joins

How to join result sets without using union or "or" in where condition.?

I have a tool which can't accept union operator or " or " conditional operator in where function
I have two queries
First query
Select * from tableA A left outer join tableB B on A.a1=B.b1 where A.a1 =20200131 and B.b2= 'monkey'
2nd query
Select * from tableA where A.a1 =20200131 and A.a3 ='Tom`
Combined query using "or" operator below
Select * from tableA A left outer join tableB B on A.a1=B.b1 where B.b2= 'monkey' or A.a3 ='Tom'
But I want a query without using "or" operator and union
Simple queries possibly involving joins or subqueries is expected
Try inserting both the resultsets into new table and selecting the table
Select * into tableB from tableA A left outer join tableB B on A.a1=B.b1 where
A.a1
=20200131 and B.b2= 'monkey'
insert into tableB
Select * from tableA where A.a1 =20200131 and A.a3 ='Tom'
select * from tableB
I think without the use of UNION/OR, will lead to more complex query. You can consider the following solution.
SELECT *
FROM tableA a
where a.a1=20200131
and ( exists (select null from tableB b
WHERE a.a1 = b.b1
and b.b2='monkey')
or exists (SELECT null FROM tableA c
WHERE a.a1 = c.a1
AND c.a3 = 'Tom'
)
)
Or you can create temp table then insert the output of both the queries.

Delete distinct multiple columns in sql

I have Query in Access that I'm building in SQL Server.
Access:
DELETE DISTINCT * from [TableA] INNER JOIN TableB
ON [TableA].[Column1]=[TableB].[column1]
AND [TableA].[Column2]=[TableB].[column2]
I know I could use
Delete from tableA where ID in (
Select * from from [TableA] INNER JOIN TableB
ON [TableA].[Column1]=[TableB].[column1]
AND [TableA].[Column2]=[TableB].[column2])
But I get an error saying "Only one expression can be specified in the select list when the subquery is not introduced with EXISTS"
My Goal is to delete the Distinct records from the Access query mentioned at the top.
You want to delete the rows in TableA that are in TableB, according to the column matches. How about doing this:
delete from tableA
where exists (select 1
from tableB
where tableA.Column1 = tableB.Column1 and tableA.column2 = tableB.column2
);
This seems to be the intent of what you are trying to do.
In the sub-query u have to select the ID column from the respective table that is the only column u need
DELETE a
FROM tableA a
JOIN (SELECT DISTINCT Column1 ,column2
FROM tableA
WHERE EXISTS (SELECT 1
FROM tableB
WHERE tableA.Column1 = tableB.Column1
AND tableA.column2 = tableB.column2)) b
ON A.Column1 = B.Column1
AND A.column2 = B.column2

Is it possible to use IF or CASE in sql FROM statement

I have a long stored procedure and I would like to make a slight modification to the procedure without having to create a new one(for maintenance purposes).
Is it possible to use a IF or CASE in the FROM statement of the select statement to join other tables?
Like this:
from tableA a
join tableB b a.indexed = c.indexed
IF #Param='Y'
BEGIN
join tableC c a.indexed = c.indexed
END
It didn't seem to work for me. But I am wondering if this is even possible and/or if this even makes sense to do.
Thanks.
No, it is not possible. You can only accomplish this through the use of dynamic SQL.
The Curse and Blessings of Dynamic SQL
An Intro to Dynamic SQL
I would not advise using Dynamic SQL, there are most likely better ways to perform this operation but you would have to provide more info.
You can achieve something like it if you have a left outer join
Consider
declare #param bit = 1
select a.*, b.*, c.* from a
inner join b on a.id = b.a_id
left outer join c on b.id = c.b_id and #param = 1
This will return all columns from a, b, c.
Now try with
declare #param bit = 0
This will return all columns from a and b, and nulls for columns of c.
It won't work if both joins are inner.
No this is not possible. Your best bet would probably be to select from both tables and only include the data your care about. If you provide an example of what you are trying to do I can provide a better answer.
Attempt at an example:
SELECT t1.id, COALESCE(t2.name, t3.name)
FROM Table1 as t1
LEFT JOIN Table2 as t2
ON t1.id = t2.id
LEFT JOIN Table2 as t3
ON t1.id = t3.id
While what you proposed is not possible, you can play with your where conditions:
from tableA a
inner join tableB b ON a.indexed = c.indexed
left join tableC c ON a.indexed = c.indexed AND 1 = CASE #Param WHEN 'Y' THEN 1 ELSE 0 END
More performant would be to just doing a big
IF #Param='Y' THEN
from tableA a
inner join tableB b ON a.indexed = c.indexed
ELSE
from tableA a
inner join tableB b ON a.indexed = c.indexed
left join tableC c ON a.indexed = c.indexed
You haven't revealed you SELECT clause. The essence of what you want is as follows:
SELECT indexed
FROM tableA
INTERSECT
SELECT indexed
FROM tableB
INTERSECT
SELECT indexed
FROM tableC
WHERE #Param = 'Y'
Then use this table expression as dictated by your SELECT clause e.g. say you only want to project tableA:
WITH T
AS
(
SELECT indexed
FROM tableA
INTERSECT
SELECT indexed
FROM tableB
INTERSECT
SELECT indexed
FROM tableC
WHERE #Param = 'Y'
)
SELECT *
FROM tableA
WHERE indexed IN ( SELECT indexed FROM T );