*=* join? Is there such a thing? [duplicate] - sql

This question already has answers here:
SQL JOIN and different types of JOINs
(6 answers)
Closed 3 years ago.
I need run a query that is like an left/right outer join. In other words I need all rows from both the left and right tables. But I don't need a cartesian product (cross join). I need to match on, in my case, email address. So given that, I have to output all rows from the left table, join the right table on email address, but all rows that do not match from either the left or right table need to be output as well with nulls for the fields from the opposite table. Sort of like a = join if there were such a thing, or left-righ outer join.
As for what I've tried: Google Searches. But didn't find anything. Cross apply might work, but I cannot wrap my brain around how that is any different from a join.
Example theoretical left-right join:
select users.*, contacts.*
from users
left-right join contacts on users.emailAddress = contacts.emailAddress
So if users contains:
----------------------------------
|emailAddress | firstName |
----------------------------------
|k#company.com | ken |
|b#enterprise.com | bill |
|j#establishment.com | joe |
----------------------------------
And contacts contains:
--------------------------------
|emailAddress | optedOut |
--------------------------------
|z#bigcompany.com | 0 |
|b#enterprise.com | 1 |
|h#smallcompany.com | 1 |
--------------------------------
The output should look like:
------------------------------------------------------------------
|emailAddress | firstName |emailAddress | optedOut |
------------------------------------------------------------------
|k#company.com | ken | NULL | NULL |
|b#enterprise.com | bill | b#enterprise.com | 1 |
|j#establishment.com | joe | NULL | NULL |
|NULL | NULL | z#bigcompany.com | 0 |
|NULL | NULL | h#smallcompany.com | 1 |
------------------------------------------------------------------

It's called a "full outer join". Your query should look like:
select users.*, contacts.*
from users
full outer join contacts on users.emailAddress = contacts.emailAddress

Related

SQL not returning values where null in another table

I'm trying to use the SQL join function to grab information from multiple tables.
My issue is I can't seem to get the desired result.
select a.DRINKER, sum(C.PRICE)
from DRINKERS a
left join ORDERS b on a.DRINKER = b.DRINKER
join SERVES c on b.PUB = c.PUB and d.DRINK = c.DRINK
group by a.DRINKER;
This gives the following results
----------------------
|DRINKER|sum(C.PRICE)|
----------------------
| BOB | 200.10 |
| NED | 172.50 |
| JOE | 270.90 |
| TIM | 80.10 |
----------------------
However I want this to be giving all of the people in a.DRINKER like such:
----------------------
|DRINKER|sum(C.PRICE)|
----------------------
| BOB | 200.10 |
| NED | 172.50 |
| JOE | 270.90 |
| TIM | 80.10 |
| PAT | null |
| ANN | null |
----------------------
Any guidance would be appreciated and if you could also explain the logic behind the changes that would be greatly appreciated as I wanna learn what I should be doing! Thanks in advance!
Even though you got a left join between DRINKERS and ORDERS, the join between ORDERS and SERVES, will filter out any nulls obtained in the first left join.
To fix this you could try by further left joining the tables
select a.DRINKER, sum(C.PRICE)
from DRINKERS a
left join ORDERS b on a.DRINKER = b.DRINKER
left join SERVES c on b.PUB = c.PUB and d.DRINK = c.DRINK
group by a.DRINKER;

How to select table with a concatenated column?

I have the following data:
select * from art_skills_table;
+----+------+---------------------------+
| ID | Name | skills |
+----+------+---------------------------|
| 1 | Anna | ["painting","photography"]|
| 2 | Bob | ["drawing","sculpting"] |
| 3 | Cat | ["pastel"] |
+----+------+---------------------------+
select * from computer_table;
+------+------+-------------------------+
| ID | Name | skills |
+------+------+-------------------------+
| 1 | Anna | ["word","typing"] |
| 2 | Cat | ["code","editing"] |
| 3 | Bob | ["excel","code"] |
+------+------+-------------------------+
I would like to write an SQL statement which results in the following table.
+------+------+-----------------------------------------------+
| ID | Name | skills |
+------+------+-----------------------------------------------+
| 1 | Anna | ["painting","photography","word","typing"] |
| 2 | Bob | ["drawing","sculpting","excel","code"] |
| 3 | Cat | ["pastel","code","editing"] |
+------+------+-----------------------------------------------+
I've tried something like SELECT * from art_skills_table LEFT JOIN computer_table ON name. However it doesn't give what I need. I've read about array_cat but I'm having a bit of trouble implementing it.
if the skills column from both tables are arrays, then you should be able to get away with this:
SELECT a.ID, a.name, array_cat(a.skills, c.skills)
FROM art_skills_table a LEFT JOIN computer_table c
ON c.id = a.id
That said, While you used LEFT join in your sample, I think either an INNER or FULL (OUTER) join might serve you better.
First, i wondered why the data are stored in such a model.
Was of the opinion that NoSQL databases lack ability for joins and ...
... a semantic triple would be in the form of subject–predicate–object.
... a Key-value (KV) stores use associative arrays.
... a relational database would be normalized.
A few information about the use case would have helped.
Nevertheless, you can select the data with CONCAT and REPLACE for the desired form.
SELECT art_skills_table.ID, computer_table.name,
CONCAT(
REPLACE(art_skills_table.skills, '}',','),
REPLACE(computer_table.skills, '{','')
)
FROM art_skills_table JOIN computer_table ON art_skills_table.ID = computer_table.ID
The query returns the following result:
+----+------+--------------------------------------------+
| ID | Name | Skills |
+----+------+--------------------------------------------+
| 1 | Anna | {"painting","photography","word","typing"} |
| 2 | Cat | {"drawing","sculpting","code","editing"} |
| 3 | Bob | {"pastel","excel","code"} |
+----+------+--------------------------------------------+
I've used the ID for the JOIN, even though Bob has different values.
The JOIN should probably be done over the name.
JOIN computer_table ON art_skills_table.Name = computer_table.Name
BTW, you need to tell us what SQL engine you're running on.

SQL relationships, multiple methods, same result? Select, From, Where OR Select, From, Join, Where

I've got 2 tables, a questions table and an answers table with the following example data:
+-----------------------------------+
| Questions |
+----+------------------------------+
| id | title |
+----+------------------------------+
| 1 | What is your favourite game? |
| 2 | What is your favourite food? |
+----+------------------------------+
+-------------------------------------------------+
| Answers |
+----+------------------------------+-------------+
| id | text | question_id |
+----+------------------------------+-------------+
| 1 | The Last Of Us | 1 |
| 2 | PlayerUnknowns Battlegrounds | 1 |
| 3 | Uncharted | 1 |
| 4 | KFC | 2 |
| 5 | Pizza | 2 |
+----+------------------------------+-------------+
Creating a one to many relationship as in one question can have many answers, I can do any of the following:
SELECT
id, text
FROM
answers
WHERE
question_id = 1
Or:
SELECT
answers.id, answers.text
FROM
answers
JOIN
questions
ON
answers.question_id = questions.id
WHERE
questions.id = 1
Or:
SELECT
answers.id, answers.text
FROM
questions
JOIN
answers
ON
questions.id = answers.question_id
WHERE
questions.id = 1
Which all return the following (expected) results:
+-----------------------------------+
| Results |
+----+------------------------------+
| id | text |
+----+------------------------------+
| 1 | The Last Of Us |
| 2 | PlayerUnknowns Battlegrounds |
| 3 | Uncharted |
+----+------------------------------+
Should any of them be avoided? Is there a preferred way of doing this? Just curious about the dos and don’ts of querying relationships in general really.
If you only want to get the answers, don't involve the questions table.
Just select from the answers.
Adding unused tables into your query makes no sense at all -
It makes the query harder to read, thus harder to maintain,
and It makes the database work harder (though modern databases might just optimize the unused parts of the query away) to get the same results.
If you want to imply relationship between "questions" and "answers" table then you can make id column from "questions" table as Primary key and
question_id column from "answers" as Foreign key
and you use JOIN when you need data(columns) from more than one table
in your case if you want title column to be included then you can JOIN tables

Use JOIN on multiple columns multiple times

I am trying to figure out the best way to use a JOIN in MSSQL in order to do the following:
I have two tables. One table contains technician IDs and an example of one data set would be as follows:
+--------+---------+---------+---------+---------+
| tagid | techBid | techPid | techFid | techMid |
+--------+---------+---------+---------+---------+
| 1-1001 | 12 | 0 | 11 | 6 |
+--------+---------+---------+---------+---------+
I have another table that stores the names of these technicians:
+------+-----------+
| TTID | SHORTNAME |
+------+-----------+
| 11 | Steven |
| 12 | Mark |
| 6 | Pierce |
+------+-----------+
If the ID of a technician in the first table is 0, there is no technician of that type for that row (types are either B, P, F, or M).
I am trying to come up with a query that will give me a result that contains all of the data from table 1 along with the shortnames from table 2 IF there is a matching ID, so the result would look something like the following:
+--------+---------+---------+---------+---------+----------------+----------------+----------------+----------------+
| tagid | techBid | techPid | techFid | techMid | techBShortName | techPShortName | techFShortName | techMShortName |
+--------+---------+---------+---------+---------+----------------+----------------+----------------+----------------+
| 1-1001 | 12 | 0 | 11 | 6 | Mark | NULL | Steven | Pierce |
+--------+---------+---------+---------+---------+----------------+----------------+----------------+----------------+
I am trying to use a JOIN to do this, but I cannot figure out how to join on multiple columns multiple times to where it would look something like
Select table1.tagid, table1.techBid, table1.techPid, table1.techFid, table1.techMid, table2.shortname
FROM table1
INNER JOIN table2 on //Dont know what to put here
You need to use left joins like this:
Select table1.tagid, table1.techBid, table1.techPid, table1.techFid, table1.techMid,
t2b.shortname, t2p.shortname, t2f.shortname, t2m.shortname,
FROM table1
LEFT JOIN table2 t2b on table1.techBid = t2b.ttid
LEFT JOIN table2 t2p on table1.techPid = t2p.ttid
LEFT JOIN table2 t2f on table1.techFid = t2f.ttid
LEFT JOIN table2 t2m on table1.techMid = t2m.ttid
you just do mutiple left join
select tech.techPid, techPname.SHORTNAME
, tech.techFid, techFname.SHORTNAME
from tech
left join techName as techPname
on tech.techPid = techPname.TTID
left join techName as techFname
on tech.techFid = techFname.TTID

SQL LEFT JOIN help

My scenario: There are 3 tables for storing tv show information; season, episode and episode_translation.
My data: There are 3 seasons, with 3 episodes each one, but there is only translation for one episode.
My objetive: I want to get a list of all the seasons and episodes for a show. If there is a translation available in a specified language, show it, otherwise show null.
My attempt to get serie 1 information in language 1:
SELECT
season_number AS season,number AS episode,name
FROM
season NATURAL JOIN episode
NATURAL LEFT JOIN episode_trans
WHERE
id_serie=1 AND
id_lang=1
ORDER BY
season_number,number
result:
+--------+---------+--------------------------------+
| season | episode | name |
+--------+---------+--------------------------------+
| 3 | 3 | Episode translated into lang 1 |
+--------+---------+--------------------------------+
expected result
+-----------------+--------------------------------+
| season | episode| name |
+-----------------+--------------------------------+
| 1 | 1 | NULL |
| 1 | 2 | NULL |
| 1 | 3 | NULL |
| 2 | 1 | NULL |
| 2 | 2 | NULL |
| 2 | 3 | NULL |
| 3 | 1 | NULL |
| 3 | 2 | NULL |
| 3 | 3 | Episode translated into lang 1 |
+--------+--------+--------------------------------+
Full DB dump
http://pastebin.com/Y8yXNHrH
I tested the following on MySQL 4.1 - it returns your expected output:
SELECT s.season_number AS season,
e.number AS episode,
et.name
FROM SEASON s
JOIN EPISODE e ON e.id_season = s.id_season
LEFT JOIN EPISODE_TRANS et ON et.id_episode = e.id_episode
AND et.id_lang = 1
WHERE s.id_serie = 1
ORDER BY s.season_number, e.number
Generally, when you use ANSI-92 JOIN syntax you need to specify the join criteria in the ON clause. In MySQL, I know that not providing it for INNER JOINs results in a cross join -- a cartesian product.
LEFT JOIN episode_trans
ON episode_trans.id_episode = episode.id_episode
AND episode_trans.id_lang = 1
WHERE id_serie=1
You probably need to move the id_lang = 1 into the LEFT JOIN clause instead of the WHERE clause. Think of it this way... for all of those rows with no translation the LEFT JOIN gives you back NULLs for all of those translation columns. Then in the WHERE clause you are checking to see if that is equal to 1 - which of course evaluates to FALSE.
It would probably be easier if you included your code in the question next time instead of in a link.
Can you try using
LEFT OUTER JOIN
instead of
NATURAL LEFT JOIN