Error in query, two select statements with left join? - sql

I have two select statements:
A: select a.1,a.2,a.3 from table1 a
B: select b.1,b.2,b.3 from table1 b
Now I join these two statements?
I tried in the below way and got error:
select *
(select a.1,a.2,a.3 from table1 a) aa
left join
(select b.1,b.2,b.3 from table1 b) bb
aa.a.1 = bb.b.1;

Within your Left Join, you need to include the ON/WHERE clause:
select *
(select a.1,a.2,a.3 from table1 a) aa
left join
(select b.1,b.2,b.3 from table1 b) bb
aa.a.1 = bb.b.1,
should be in the format:
SELECT *
(SELECT a.1, a.2, a.3 FROM table1 a) aa
LEFT JOIN
(SELECT b.1,b.2,b.3 FROM table2 b) bb
ON a.1 = b.1
WHERE ...
For more clarification, please see this image:
As it currently stands, it's quite hard to distinguish what exactly your requirements are in terms of what you want the query to return, but I op this image will visually display the syntax for each of the joins.

Numbers (a.1, a.2, i.e. columns 1 and 2 for table alias a) are usually not valid column names. Are the columns really named thus? Then you'd need something to indicate that these are column names. Depending on the dbms that could be `a.1` or "a.1" or [a.1]. Or use different names, such as num1, num2, num3, or one, two, three, etc.
EDIT: You are also missing the word ON before your criteria. And aa.a.1 is invalid, for your table alias is now aa and the column name is still "1" and the table alias a is no longer known. So it must be a."1" instead. Moreover you are missing the keyword FROM for your first derived table.
select *
from (select a."1", a."2", a."3" from table1 a) aa
left join (select b."1", b."2", b."3" from table1 b) bb ON aa."1" = bb."1";

Related

How to combine multiple SELECT statements into a single query & get a single result output

I have multiple SELECT queries which is ran against different tables.
The output of all the queries have the same number of rows (every query when ran individually will have the same number of rows). Is there a way I can combine the output of all these queries into a single result? (Keep out from first query and add the output of next query as a column to the output of the next query). I dont want to save these tables into database as I am just doing some validation testing.
Example:
SELECT AAA,BBB,CCC FROM Table1
SELECT Table2.DDD, Table1.AAA
FROM Table2
INNER JOIN Table1
ON Table1.AAA = Table2.AAA
I tried writing combining the query as
SELECT Table1.AAA,Table1.BBB,Table1.CCC,T1.DDD
FROM Table1,
(SELECT Table2.DDD, Table1.AAA
FROM Table2
INNER JOIN Table1
ON Table1.AAA = Table2.AAA)T1
I tried doing the above combined query, but instead of getting 11 rows as output (both queries above had result of 11 rows), I am getting 35 rows as output.
Hope the question made sense!
You'll need to specify a criteria to match each row the first query with which row of the second query.
If, for example, the column AAA is unique in both queries and you want to match rows with the same values you could do:
select a.*, b.*
from (
SELECT AAA,BBB,CCC FROM Table1
) a
full join join (
SELECT Table2.DDD, Table1.AAA
FROM Table2
INNER JOIN Table1
ON Table1.AAA = Table2.AAA
) b on b.aaa = a.aaa
If there aren't any clear matching rules, you can produce an artificial row number on each result set and use it to match rows. For example:
select
a.aaa, a.bbb, a.ccc,
b.ddd, b.aaa
from (
SELECT AAA, BBB, CCC,
row_number() over(order by aaa) as rn
FROM Table1
) a
full join join (
SELECT Table2.DDD, Table1.AAA,
row_number() over(order by table1.aaa, table2.ddd) as rn
FROM Table2
INNER JOIN Table1
ON Table1.AAA = Table2.AAA
) b on b.rn = a.rn
If you have several results and want to have all of them as additional columns you can simply use ",":
create table temp1 as select '1' as c1 from DUAL;
create table temp2 as select '2' as c2 from DUAL;
create table temp3 as select '3' as c3 from DUAL;
select a.c1, b.c2, c.c3 from temp1 a, (select c2 from temp2) b, (select c3 from temp3) c;
An alternative could also be that you want to have all the results as additional rows then you would use UNION ALL between the individual results.

Standard SQL: LEFT JOIN by two conditions using BETWEEN

I have the following query in BigQuery:
#Standard SQL
SELECT *
FROM `Table_1`
LEFT JOIN `Table_2` ON (timestamp BETWEEN TimeStampStart AND TimeStampEnd)
But I get the following Error:
Error: LEFT OUTER JOIN cannot be used without a condition that is an equality of fields from both sides of the join.
If I use JOIN instead of LEFT JOIN, it works, but I want to keep all the rows from Table_1 (so also the ones which aren't matched to Table_2)
How to achieve this?
This is absolutely stupid... but the same query will work if you add a condition that matches a column from table1 with a column from table2:
WITH Table_1 AS (
SELECT CAST('2018-08-15' AS DATE) AS Timestamp, 'Foo' AS Foo
UNION ALL
SELECT CAST('2018-09-15' AS DATE), 'Foo'
), Table_2 AS (
SELECT CAST('2018-08-14' AS DATE) AS TimeStampStart, CAST('2018-08-16' AS DATE) AS TimeStampEnd, 'Foo' AS Bar
)
SELECT *
FROM Table_1
LEFT JOIN Table_2 ON Table_1.Foo = Table_2.Bar AND Table_1.Timestamp BETWEEN Table_2.TimeStampStart AND Table_2.TimeStampEnd
See if you have additional matching criteria that you can use (like another column that links table1 and table2 on equality).
A LEFT JOIN is always equivalent to the UNION of :
the INNER JOIN between the same two arguments on the same join predicate, and
the set of rows from the first argument for which no matching row is found (and properly extended with null values for all columns retained from the second argument)
That latter portion can be written as
SELECT T1.*, null as T2_C1, null as T2_C2, ...
FROM T1
WHERE NOT EXISTS (SELECT * FROM T2 WHERE )
So if you spell out the UNION you should be able to get there.
Interesting. This works for me in standard SQL:
select *
from (select 1 as x) a left join
(select 2 as a, 3 as b) b
on a.x between b.a and b.b
I suspect you are using legacy SQL. Such switch to standard SQL. (And drop the parentheses after the between.)
The problem is:
#(Standard SQL)#
This doesn't do anything. Use:
#StandardSQL
Hi as per the documentation, "(" has a special meaning, so please try without the brackets.
SELECT * FROM Table_1
LEFT JOIN Table_2 ON Table_1.timestamp >= Table_2.TimeStampStart AND Table_1.timestamp <= Table_2.TimeStampEnd
Documentation here

Natural join with more than one common attribute in two tables [duplicate]

This question already has answers here:
Difference between natural join and inner join
(12 answers)
Closed 1 year ago.
I can understand how natural join works when the two tables have only one common attribute. What if they have two ones?
Table 1 have 3 attributes: A, B, C
Table 2 has 3 attribute: A, B, D
First two rows in table 1:
1 2 3
4 5 6
First two rows in table 2:
1 3 4
8 5 8
What is the result of a natural join between the two tables?
In the case of your two records above, nothing will be matched. It will look for the case when A & B in the left table match A & B in the right table.
Natural Join is a variant of INNER JOIN where join condition is implicit on common column from both tables. In your case, the query in Natural Join can be written as below which will not return any result since it will try to match both A and B
select *
from table1
natural join table2
The same can be written in Inner Join like below
select t1.*
from table1 t1
inner join table2 t2
on t1.a = t2.a and t1.b = t2.b
See for yourself Fiddle Demo
Actually Natural Join is something (Cross product + some condition)
The short form of natural join is:
Select * from Table_A NATURAL JOIN Table_B
So, an alternative way of writing this would be:
Select * from Table_A , Table_B where (Table_A.id = Table_B .id)
This is equivalent to Natural Join
(Table_A , Table_B) symbolises cross product
(Table_A.id = Table_B .id) symbolises common condition
I will try to explain the difference between NATURAL JOIN and INNER JOIN on the basis of use-case.
We have two tables T1(A, B, C, D) & T2(B, C, X, Y), where the alphabets (A, B, C, D, X, Y) represent fields/attributes.
CASE 1: say I have to pull all rows which have a common entry in 'C' across both tables.
query: SELECT * FROM T1 INNER JOIN T2 ON T1.C=T2.C;
EXPLAINATION ON WHY NATURAL JOIN WILL NOT WORK IN THE ABOVE CASE --
say we use NATURAL JOIN.
SELECT * FROM T1 NATURAL JOIN T2;
We know that, T1 & T2 have two similar attributes/fields ('B' and 'C')
so, NATURAL JOIN will look for all such entries where
(T1.B=T2.B) AND (T1.C=T2.C)
Only the rows which satisfy the above condition, will be included in the result set.
Whereas, we only need the rows to have a common entry for field 'C' for our purpose.
I am studying for the certification and I got this doubt also.
NATURAL JOIN ALWAYS compare the similar columns in the tables.
If you have one pair of similar columns, it will compare and it'll show the matches. Chances are higher. Now, if you have 2 pairs, it will compare and it'll bring less results. the content has to be equal. Create a table yourself and do the test

Is there a way to do a multi table query and get result just from specific tables?

I am trying to do a multi query but I don't want to use sub queries i.e:
SELECT column1
FROM table1
WHERE
EXISTS (SELECT column1 FROM table2 WHERE table1.column1 = table2.column1);)
I thought of using a JOIN but so far my best result was this:
SELECT *
FROM table1
JOIN table2 ON table1.t1id = table2.t2id
WHERE table1.id = 5;
This would be good except of the fact that I get a duplicate column (the id in table 1 and 2 are foreign keys).
How do I remove the duplicate column if possible?
UPDATE:
Table1:
tableA_ID, TABLEB_ID
1, 1
1, 4
3, 2
4, 3
TableA: ID, COL1, COL2
1, A, B
2, A, B
3, A, B
4, A, B
TableB: ID, Col3, COL4
1, C, D
2, C, D
3, C, D
4, C, D
I want to get all or some of the columns from TableA according to a condition
Sample: Lets say the condition is that tableA_ID = 1 which will result in the 2 first rows in the table then I want to get all or some of the columns in TableA that respond to the ID that I got from Table1.
Sample: The result from before was [{1,1}{1,4}] which means I want from TableA the results:
TableA.ID, TableA.COL1, TableA.COL2
1,A,B
4,A,B
The actual results I get is:
Table1.tableA_ID, Table1.TABLEB_ID, TableA.ID, TableA.COL1, TableA.COL2
1,1,1,A,B
1,4,4,A,B
Is this what you're looking for?
select a.id, a.column1, b.column2
from table1 a
left join table2 b on a.id = b.otherid;
You can't change the column list of a query based on the values it returns. It just isn't the way that SQL is designed to operate. At best, you can return all of the columns from the second table and ignore the ones that aren't relevant based on other values in that row.
I'm not even sure how a variable column list would work. In your scenario, you're looking for two discrete values separately. But that's not the only scenario: what if the condition is tableA_ID in (1,2). Would you want different numbers of columns in different rows as part of a single result set?
Getting just the columns you want (just from specific tables, as you say) is the easy part (btw -- don't use '*' if you can help it -- topic for another discussion):
SELECT
A.ID,
A.COL1,
A.COL2
FROM
TABLE1 Bridge
LEFT JOIN TABLEA A
ON Bridge.TABLEA_ID = A.ID
LEFT JOIN TABLEB B
ON Bridge.TABLEB_ID = B.ID
Getting the rows you want will be the harder part (influenced by your choice of joins, among several other things).
I think you'll need to select only the fields of table A and use a distinct clause. Rest of your query will remain as it is. i.e.
SELECT distinct table1.*
FROM table1
JOIN table2 ON table1.t1id = table2.t2id
WHERE table1.id = 5;

Is possible have different conditions for each row in a query?

How I can select a set of rows where each row match a different condition?
Example:
Supposing I have a table with a column called name, I want the result ONLY IF the first row name matches 'A', the second row name matches 'B' and the third row name matches 'C'.
Edit:
I want to do this to work without a fixed size, but in a way I can define the sequence like R,X,V,P,T and it matches the sequence, each one in a row, but in the order.
you can, but probably not in a way you would want:
if your table has a numeric id field, that is incremented with each row, you can self join that table 3 times (lets say as "a", "b" and "c") and use the join condition a.id + 1 = b.id and b.id + 1 = c.id and put you filter in a where clause like: a.name = 'A' AND b.name = 'B' AND c.name = 'C'
but don't expect performance ...
Assuming that You know how to provide a row number to your rows (ROW_NUMBER() in SQL Server, for instance), You can create a lookup (match) table and join on it. See below for explanation:
LookupTable:
RowNum Value
1 A
2 B
3 C
Your SourceTable source table (assuming You already added RowNum to it-in case You didn't, just introduce subquery for it (or CTE for SQL Server 2005 or newer):
RowNum Name
-----------
1 A
2 B
3 C
4 D
Now You need to inner join LookupTable with your SourceTable on LookupTable.RowNum = SourceTable.RowNum AND LookupTable.Name = SourceTable.Name. Then do a left join of this result with LookupTable on RowNum only. If there is LookupTable.RowNum IS NULL in final result then You know that there is no complete match on at least one row.
Here is code for joins:
SELECT T.*, LT2.RowNum AS Matched
FROM LookupTable LT2
LEFT JOIN
(
SELECT ST.*
FROM SourceTable ST
INNER JOIN LookupTable LT ON LT.RowNum = ST.RowNum AND LT.Name = ST.Name
) T
ON LT2.RowNum = T.RowNum
Result set of above query will contain rows with Matched IS NULL if row is not matching condition from LookupTable table.
I suppose you could do a sub query for each row, but it wouldn't perform well or scale well at all and would be hard to maintain.
This may be close to what your after... but I need to know where you're getting your values for A, B, C etc...
Select [insert your fields here]
FROM
(Select T1.Name, T1.Age, RowNum as t1RowNum from T T1 order by name) T1O
Full Outer JOIN
(Select T2.Name, T2.Age, RowNum as T2rowNum From T T2 order By name) T2O
ON T1O.T1RowNum+1 = T2O.T2RowNum