Why can't I select from my query? - sql

I have a query something like this (no, my tables and fields are not called by these names, but the structure is the same) -
SELECT table1.id, table2.id, table1.phone1
FROM table1 LEFT OUTER JOIN
table3 ON table3.id = table1.id LEFT OUTER JOIN
table2 ON table3.id2 = table2.id
WHERE table1.phone1 IS NOT NULL AND LTRIM(RTRIM(table1.phone1)) <> ''
UNION
SELECT table1.id, table2.id, table1.phone2
FROM table1 LEFT OUTER JOIN
table3 ON table3.id = table1.id LEFT OUTER JOIN
table2 ON table3.id2 = table2.id
WHERE table1.phone2 IS NOT NULL AND LTRIM(RTRIM(table1.phone2)) <> ''
UNION
SELECT table1.id, table2.id, table2.phone
FROM table1 LEFT OUTER JOIN
table3 ON table3.id = table1.id LEFT OUTER JOIN
table2 ON table3.id2 = table2.id
WHERE table2.phone IS NOT NULL AND LTRIM(RTRIM(table2.phone)) <> ''
It runs fine. But, when I try to select from it (which I will eventually try to manipulate with group bys, etc., but for now just tried a simple select), like so:
SELECT * FROM
( SELECT table1.id, table2.id, table1.phone1
FROM table1 LEFT OUTER JOIN
table3 ON table3.id = table1.id LEFT OUTER JOIN
table2 ON table3.id2 = table2.id
WHERE table1.phone1 IS NOT NULL AND LTRIM(RTRIM(table1.phone1)) <> ''
UNION
SELECT table1.id, table2.id, table1.phone2
FROM table1 LEFT OUTER JOIN
table3 ON table3.id = table1.id LEFT OUTER JOIN
table2 ON table3.id2 = table2.id
WHERE table1.phone2 IS NOT NULL AND LTRIM(RTRIM(table1.phone2)) <> ''
UNION
SELECT table1.id, table2.id, table2.phone
FROM table1 LEFT OUTER JOIN
table3 ON table3.id = table1.id LEFT OUTER JOIN
table2 ON table3.id2 = table2.id
WHERE table2.phone IS NOT NULL AND LTRIM(RTRIM(table2.phone)) <> '' )
I get the error:
Incorrect syntax near ')'.
What am I doing wrong?

You missed naming the subselect. Close with something like ...) sub_query_name.

Related

Left outer join involving three tables

From the 3 tables below I need to find 'John', who has a bike but not a car.
I'm trying to use this syntax
Select <> from TableA A left join TableB B on A.Key = B.Key where B.Key IS null
so in practise I create a left join from the two tables but i'm bit confused how the where B.Key IS null fits in my query.
select t1.name from
(table1 t1 join table3 on table3.table1id = t1.id join table2 t2 on table3.table2id = t2.id)
left join
(table1 t11 join table3 on table3.table1id = t11.id join table2 t22 on table3.table2id = t22.id)
on t1.name = t11.name where t2.name = 'Bike' and t22.name = 'Car';
Table1
ID
NAME
1
John
2
Nick
Table2
ID
NAME
1
Bike
2
Car
Table3
table1ID
table2ID
1
1
2
1
2
2
If you want your query to run at all cost you can go for something monstrous like this:
select name from table1
left join (select table1Id, table2.id as CarId from table3 join table2 on table2.id = table3.table2Id where table2.name = 'Car') c on id=c.table1Id
left join (select table1Id, table2.id as BikeId from table3 join table2 on table2.id = table3.table2Id where table2.name = 'Bike') b on id=b.table1Id
where CarId is null and BikeId is not null
https://dbfiddle.uk/pbftUJQL
But at the end it is a rough equivalent of straightforward
select name from table1
where not exists (select * from table3 join table2 on table2.id = table3.table2Id where table1.id=table3.table1Id and table2.name = 'Car')
and exists (select * from table3 join table2 on table2.id = table3.table2Id where table1.id=table3.table1Id and table2.name = 'Bike')
You must analyze query plans to choose variant that offer better performance. It may be this one:
select table1.name from table1 join table3 on table1.id=table3.table1Id join table2 on table2.id = table3.table2Id
where table2.name = 'Bike'
and not exists (select * from table3 t3 join table2 t2 on t2.id = t3.table2Id where table1.id=t3.table1Id and t2.name = 'Car')
From the 3 tables below I need to find John who has a bike but not a
car.
I would rather use this approach, it allows you to include additional criteria (e.g. has a bike and a truck but not a car) by modifying the having clause instead of adding additional joins:
select table1.id, table1.name
from table3
join table1 on table3.table1id = table1.id
join table2 on table3.table2id = table2.id
group by table1.id, table1.name
having count(case when table2.name = 'bike' then 1 end) > 0
and count(case when table2.name = 'car' then 1 end) = 0
PS: your original query could be written like this (it was missing aliases and where clause):
select *
from table1
left join (
table3 as table3_bike join
table2 as table2_bike on table3_bike.table2id = table2_bike.id
) on table3_bike.table1id = table1.id and
table2_bike.name = 'bike'
left join (
table3 as table3_car join
table2 as table2_car on table3_car.table2id = table2_car.id
) on table3_car.table1id = table1.id and
table2_car.name = 'car'
where table2_bike.id is not null
and table2_car.id is null
This query has the potential to grow exponentially e.g. if John has two bikes and two cars it'll return 2 x 2 = 4 rows for John. Relational division using exists or having is recommended.

Teradata update with left join and inner join

I need to bring the below sample code from mssql to Teradata. Please let me know how to convert it.Sample code -
Update table1
set table1.name = table3.name
from table1
inner join table2
on table2.id = table1.id
left join table3
on table2.id = table3.id where table3.name is null
It's ugly, but this should work. You can get around Teradata not allowing outer joins in an update by using a derived table.
update table1
from table1,
(select <column list> from table2 left join table3 on table2.id = table3.id) t
set ...
where
table1.id = t.id
and t.name is null
Like the others mentioned, you should check your NULL condition. Nevertheless, here's one more option:
Update table1
FROM (
select table1.id, table3.name
from table1
inner join table2
on table2.id = table1.id
left join table3
on table2.id = table3.id where table3.name is null
) src
SET table1.name = src.name
WHERE table1.id = src.id
You just move your original source query into a "src" sub-query and update from it. Just make sure in your "src" query you only have one row for each table1.id value so you don't get target row updated by multiple source rows errors.
I think your logic is better handled by not exists:
Update table1
set table1.name = null
where not exists (select 1
from table2 join
table3
on table2.id = table3.id
where table2.id = table1.id
);
This is not exactly what your query specifies -- this will update table1.name when there is no match in table2. If that is an issue, you can do:
update table1
set table1.name = null
where exists (select 1
from table2
where table2.id = table3.id
) and
not exists (select 1
from table2 join
table3
on table2.id = table3.id
where table2.id = table1.id
);

subquery in SELECT without JOIN in Hive?

I know Hive doesn't support this
SELECT (CASE WHEN table1.id in (SELECT table1.id
from table1,table2
where table1.id = table2.id and table2.company like '%My Company%')
THEN table1.email
ELSE regexp_replace(table1.email, substr(table1.email, 1), 'XXXX')
END) as email, table1.id
FROM table1
Hive cannot do SELECT within SELECT (subquery in SELECT).
But let say for some restriction I cannot do JOIN after FROM clause. Is there a "creative" way to do this? I was thinking about parsing and passing a "static list" from SELECT table1.id from table1,table2 where table1.id = table2.id and table2.company like '%My Company%' in a separate query. But this could go up to thousands.
if you could use a select for a join the you could use a left join and check for null value
SELECT case when t1.id is null
then regexp_replace(table1.email, substr(table1.email, 1), 'XXXX')
else table1.email
end
, table1.id
FROM table1
left join (
SELECT table1.id
from table1,table2
where table1.id = table2.id
and table2.company like '%My Company%'
) t on table1.id = t.id

How to join 3 tables in sql with or condition

I have 3 tables:
table1
inner join with table2; or:
inner join with table3
The query:
select table1.x
from table1 right outer join
table2
on table1.x = table2.x right outer join
table3
on table1.x = table3.x
but I can only see x values that are in both table2 and table3
Use left join, not right join, along with an appropriate filter condition:
select table1.x
from table1 left join
table2
on table1.x = table2.x left join
table3
on table1.x = table3.x
where table2.x is not null or table3.x is not null;
You might consider writing this using exists:
select t1.*
from table1 t1
where exists (select 1 from table2 t2 where t2.x = t1.x) or
exists (select 1 from table3 t3 where t3.x = t1.x);
That seems like a more natural way to implement your logic -- and you won't get duplicates when x is duplicated in table2 or table3.

sql left outer join order by column in left table but preserve all rows

I have the following:
SELECT
table1.id
FROM
table1
LEFT OUTER JOIN table2 ON table2.table1_id = table1.id
WHERE
(table1.entry_id=2)
AND
parent_id=0
ORDER BY
SUM(table2.column1) - SUM(table2.column2)
Works fine until I add the 'order by', I need it to get all relevant rows from table1, even if they have unmatched rows in table2, ordering would place them at the bottom.
Try this instead:
SELECT
t1.id
FROM table1 AS t1
LEFT OUTER JOIN
(
SELECT table1_id, SUM(column1) sum1, SUM(column2) sum2
FROM table2
GROUP BY table1_id
) AS t2 ON t2.table1_id = t.id
AND t1.entry_id = 2
AND t1.parent_id = 0
ORDER BY t2.sum1 - t2.sum2;