Inner Join with similar IDs - sql

I have two tables, say:
Table 1
id, name, place
1, a, b
2, c, d
3, e, f
Table 2
id,text
1, hello
1, bye
1, what
2, tired
Desired Output
id, name, place, text
1, a, b, hello or bye or what (any one of the three)
2, c, d, tired
I have seen a lot of posts but I couldn't find anything similar. I am new to SQL/Postgresql. I am doing it in PostgreSQL.

You could use DISTINCT ON here and arbitrarily just take the alphabetically lowest text from the second table:
SELECT DISTINCT ON (t1.id) t1.id, t1.name, t1.place, t2.text
FROM Table1 t1
INNER JOIN Table2 t2
ON t1.id = t2.id
ORDER BY
t1.id,
t2.text;
Demo

You can aggregate multiple values in an array and pick a random value (postgres syntax):
select t1.id, (array_agg(t2.text))[floor(random() * count(t2.text) + 1)::int]
from table1 t1
inner join table2 t2 on t1.id = t2.id
group by t1.id
Or a bit faster, but will pick first value only:
select t1.id, (array_agg(t2.text))[1]
from table1 t1
inner join table2 t2 on t1.id = t2.id
group by t1.id

You would write something along the lines of
select t1.id, name, place, text from table 1 as t1
join table 2 as t2 on t2.id = t1.id
group by t1.id

Related

SQL — Union two tables but Join on one of the columns

I have two tables that look like this:
Table 1:
name | event | country
Table 2:
name | event
There are no overlapping rows between Table 1 and Table 2, because of the 'event' column. I wanted to union Table 1 with Table 2 since there are no overlaps, but I also want to fill in 'country' for Table 2 using the values from Table 1, with 'name' as the Join key. How do I do this?
If the relation of the 2 tables is 1:1 you can use UNION ALL for table1 and a query that joins (with a left join just in case there are no matches) table2 to table1 to retrieve the value of the column country:
select t1.* from table1 t1
union all
select t2.*, t1.country
from table2 t2 left join table1 t1
on t1.name = t2.name
or with a correlated subquery:
select t1.* from table1 t1
union all
select t2.*, (select t1.country from table1 t1 where t1.name = t2.name)
from table2 t2
Try this
SELECT * FROM TABLE1 t1
UNION
Select t2.*, t1.country from table2 t2
Join table1 t1 on t2.name=t1.name
This sounds like a full join:
select *
from table1 t1 full join
table2 t2
using (name, event);
If your database doesn't support full join, you can use:
select t1.name, t1.event, t1.country
from table1 t1
union all
select t2.name, t2.event, null
from table2 t2
where not exists (select 1 from table1 t1 where t1.name = t2.name and t1.event = t2.event);

not in operator in SQL

there is 2 tables
table1
ID
1
2
4
6
7
TABLE2
2
4
6
i want those number from table1 which is not in table2 how i do this ?
i try this
select id from table1 t1
inner join table2 t2 on t1.id=t2.id
where t1.id not in (select id from table2)
but this is not working
SELECT t1.id
FROM table1 t1
LEFT JOIN table2 t2 ON t2.id = t1.id
WHERE t2.id IS NULL
Conceptually, we select all rows from table1 and for each row we attempt to find a row in table2 with the same value for the id column. If there is no such row, we just leave the table2 portion of our result empty for that row. Then we constrain our selection by picking only those rows in the result where the matching row does not exist. Finally, We ignore all fields from our result except for the id column (the one we are sure that exists, from table1).
try this:
select id from table1 t1 where t1.id not in (select t2.id from table2 t2)
You don't need to join the two tables in this case. You could just do
select id from table1 A where A.id not in (select B.id from table2 B);
You could also just simply use the sql set difference EXCEPT operator to achieve this
(select id from table1) except (select id from table2);
Use NOT IN or NOT EXISTS
select id from table1 t1
where t1.id not in (select id from table2)
select id from table1 t1
where not exists (select id from table2 where id = t1.id)

how to use multiple select statements in stored procedure as columns in Resultset

I have a stored procedure which has multiple sql statments,
SELECT X,ID FROM TABLE1
SELECT Y,ID FROM TABLE2
SELECT Z,ID FROM Table3
WHEN I EXECUTE the above statements form procedure
My result set should be
ID, X,Y,Z will the columns and 1,10,20,30 will be the values of 1st row , 6, 40, 50, 60 will be the values of second row, ... goes on
I am using SQL SERVER 2005
Is it possible to do so ?
If there's only 1 row in each table you can just do the following:
select
(select X from table1) X,
(select Y from table2) Y,
(select Z from table3) Z;
Example SQLFiddle
For your second example, you can merely use join:
select
t1.id,
t1.X,
t2.Y,
t3.Z
from
table1 t1
inner join
table2 t2
on t1.id = t2.id
inner join
table t3
on t2.id = t3.id;
If the tables are really place holders for much larger queries, it might read more easily to use with
;with t1 as (
select id, X from table1
), t2 as (
select id, Y from table2,
), t3 as (
select id, Z from table3
) select
t1.id,
t1.X,
t2.Y,
t3.Z
from
t1
inner join
t2
on t1.id = t2.id
inner join
t3
on t2.id = t3.id;

SQL Join Question

I have an interesting question for an SQL Join. I have 2 tables, examples below:
Table1: ID (int), Value(string)
Table2: ID (int), ForeignID(int), (Value)
The field ForeignID in Table2 is the foreign key of the ID in Table1. For a given entry in Table1, I have multiple entries in Table2 as follows:
Table1:
ID, Value
0, "Hello World"
1, "Bonjour"
Table2:
ID, ForeignID, Value
0, 0, "First entry"
1, 0, "Second entry"
2, 1, "Third entry"
If I do an inner join such as
SELECT Table1.Value, Table2. Value FROM
Table1 INNER JOIN Table2 ON Table1.ID = Table2.ForeignID
I would get
Hello world, First entry
Hello world, Second entry
Bonjour, Third entry
Is there a way to only get the TOP entry in Table2 such as:
Hello world, First entry
Bonjour, Third entry
This works too:
SELECT Table1.value
, Table2.value
FROM Table1
INNER JOIN Table2 ON Table1.id = Table2.foreignID
INNER JOIN (
SELECT MIN(ID) AS ID, ForeignID
FROM Table2
GROUP BY ForeignID
) MinID ON Table2.foreignid = MinID.foreignid
AND Table2.id = MinID.id
SELECT
t1.Value,
(
SELECT TOP 1 t2.Value FROM Table2 t2
WHERE t2.ForeignID = t1.ID
ORDER BY t2.ID ASC
)
FROM Table1 t1
SELECT Table1.Value,
(SELECT TOP 1 Table2.Value
FROM Table2
WHERE Table2.ForeignID = Table1.ID)
FROM Table1
Since you tagged SQL, here is the ANSI SQL query (which should work on SQL Server 2005+) :
WITH TT (ID, ForeignID, Value, N) AS (
SELECT ID, ForeignID, Value,
ROW_NUMBER() OVER(PARTITION BY ForeignID ORDER BY ID)
FROM Table2
)
SELECT T1.Value, T2.Value
FROM Table1 T1
INNER JOIN TT T2
ON T1.ID = T2.ForeignID
AND T2.N = 1;
It uses a Common Table Expression and a windowing function.
Here is another variation that makes sure that table2 in joined to table1 on the proper key.
SELECT t1.Value,
t2.Value
FROM Table1 t1
INNER JOIN Table2 t2
ON t2.ForeignID = (SELECT MIN(sub.ForeignID)
FROM Table2 sub WHERE sub.ForeignID = t1.ID)
Edit, actually, scratch that. Tamila's answer looks better to me.
If you can add a boolean is_first flag to your table2 then things become a lot easier and this would do the job for you:
SELECT table1."value", table2."value"
FROM table1
INNER JOIN table2 ON table1.id = table2.foreign_id
WHERE table2.is_first = true
I don't know if Daniel's, cgatian's or Leons' answers will work for your database. I'm on Postgres and it doesn't work for me.

Merge and add values from two tables

Is it possible to craft a query that adds values within two tables:
For example, say you have two tables
id value
-- -----
a 1
c 2
d 3
f 4
g 5
and
id value
-- -----
a 1
b 2
c 3
d 4
e 5
Then when you 'add' the two tables you would get the result where the id's match. So, a=1+1=2, and simply the same result where they don't. So the query would return:
id value
-- -----
a 2
b 2
c 5
d 7
e 5
f 4
g 5
maybe something like
select coalesce(t1.id, t2.id) as id, (coalesce(t1.value, 0) + coalesce(t2.value, 0)) as value
from table1 t1 full outer join table2 t2 on t1.id = t2.id
Use:
SELECT x.id,
SUM(x.value)
FROM (SELECT t.id,
t.value
FROM TABLE_1 t
UNION ALL
SELECT t2.id,
t2.value
FROM TABLE_2 t2) x
GROUP BY x.id
You could do it like this - but the other answers are probably swifter:
SELECT t1.id, t1.value + t2.value AS value
FROM t1 INNER JOIN t2 ON t1.id = t2.id
UNION
SELECT t1.id, t1.value
FROM t1
WHERE t1.id NOT IN (SELECT t2.id FROM t2)
UNION
SELECT t2.id, t2.value
FROM t2
WHERE t2.id NOT IN (SELECT t1.id FROM t1)
SELECT
COALESCE(t1.id, t2.id) AS id,
COALESCE(t1.value, 0) + COALESCE(t2.value, 0) AS value
FROM
t1
FULL OUTER JOIN
t2 ON t1.id = t2.id
OR
SELECT
foo.id,
COALESCE(t1.value, 0) + COALESCE(t2.value, 0) AS value
FROM
(
SELECT t1.id FROM t1
UNION
SELECT t2.id FROM t2
) foo
LEFT JOIN
t1 ON foo.id = t1.id
LEFT JOIN
t2 ON foo.id = t2.id
SELECT ISNULL(T1.Col1.T2.Col1) as ID, (ISNULL(T1.Col2,0) + ISNULL(T2.Col2,0)) as SumCols
FROM T1 OUTER JOIN T2 ON T1.Col1 = T2.Col2
No grouping or anything. It handles the following cases
if an id is in T1 but not in T2 you will get the value in T1 and vice versa. This handles bi-directional inclusion.
If an ID is in both you will get the sum