SQL - Join with default if it's not possible to match - sql

I have two tables which look like this:
Table 1:
+---------+---------+-------------+
| Activity| Area | Responsible |
+---------+---------+-------------+
| Cooking | Meat | Peter |
| Cooking | Vegan | Sia |
| Cleaning| Kitchen | Paul |
| Cleaning| Toilets | Selina |
+---------+---------+-------------+
Table 2:
+---------+---------+-------------+
| Activity| Area | Day |
+---------+---------+-------------+
| Cooking | Meat | Monday |
| Cooking | Vegan | Monday |
| Cleaning| Garden | Friday |
| Cleaning| Toilets | Friday |
+---------+---------+-------------+
Now I want an SQL to join them, so that I can see the responsible persons for each day.
I think the standard SQL would look something like this:
SELECT DAY, ACTIVITY, RESPONSIBLE
FROM TABLE_2 2
LEFT JOIN TABLE_1 1
ON 1.ACTIVITY = 2.ACTIVITY AND 1.AREA = 2.AREA
But now there are some rows which can not be joint (e.g. Cleaning Garden).
In that case (if it is not possible to join) I want always Peter to be responsible for it.
Can I do that in one join (maybe with a CASE statement?) or how would you do this?

Don't use numbers for table names, even if DB2 allows it. Numbers should be numbers.
You are looking for COALESCE():
SELECT t2.DAY, t2.ACTIVITY, COALESCE(t1.RESPONSIBLE, 'Peter') as Responsible
FROM TABLE_2 t2 LEFT JOIN
TABLE_1 t1
ON t1.ACTIVITY = t2.ACTIVITY AND t1.AREA = t2.AREA;

Related

SQL - specific requirement to compare tables

I'm trying to merge 2 queries into 1 (cuts the number of daily queries in half): I have 2 tables, I want to do a query against 1 table, then the same query against the other table that has the same list just less entries.
Basically its a list of (let's call it for obfuscation) people and hobby. One table is ALL people & hobby, the other shorter list is people & hobby that I've met. Table 2 would all be found in table 1. Table 1 includes entries (people I have yet to meet) not found in table 2
The tables are synced up from elsewhere, what I'm looking to do is print a list of ALL people in the first column then print the hobby ONLY of people that are on both lists. That way I can see the lists merged, and track the rate at which the gap between both lists is closing. I have tried a number of SQL combinations but they either filter out the first table and match only items that are true for both (i.e. just giving me table 2) or just adding table 2 to table 1.
Example of what I'm trying to do below:
+---------+----------+--+----------+---------+--+---------+----------+
| table1 | | | table2 | | | query | |
+---------+----------+--+----------+---------+--+---------+----------+
| name | hobby | | activity | person | | name | hobby |
| bob | fishing | | fishing | bob | | bob | fishing |
| bill | vidgames | | hiking | sarah | | bill | |
| sarah | hiking | | planking | sabrina | | sarah | hiking |
| mike | cooking | | | | | mike | |
| sabrina | planking | | | | | sabrina | planking |
+---------+----------+--+----------+---------+--+---------+----------+
Normally I'd just take the few days to learn SQL a bit better however I'm stretched pretty thin at work as it is!
I should mention the table 2 is flipped and the headings are all unique (don't think this matters)!
I think you just want a left join:
select t1.name, t2.activity as hobby
from table1 t1 left join
table2 t2
on t1.name = t2.person;

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.

Joining Two SQL Tables on Different Databases [duplicate]

This question already has answers here:
Can we use join for two different database tables?
(2 answers)
Closed 4 years ago.
I have two tables on two separate databases. We will call them Table1 and Table2.
Table1:
+----------+----------+----------+---------+------+----------+
| UniqueID | Date1 | Date2 | Fruit | Cost | Duration |
+----------+----------+----------+---------+------+----------+
| 1 | 09/10/18 | 10/20/18 | Apples | 1.50 | 7 |
| 2 | 09/18/18 | 10/25/18 | Oranges | 1.75 | 10 |
| 3 | 10/01/18 | 10/30/18 | Bananas | 2.00 | 10 |
+----------+----------+----------+---------+------+----------+
Table2:
+----------+---------+------+----------+-----------+
| Date1 | Fruit | Cost | Duration | New Price |
+----------+---------+------+----------+-----------+
| 09/10/18 | Savory | 1.50 | 7 | 1.90 |
| 09/18/18 | Citrusy | 1.75 | 10 | 2.50 |
| 10/01/18 | Mealy | 2.00 | 10 | 2.99 |
| 10/20/18 | Savory | 1.50 | 7 | 3.90 |
| 10/25/18 | Citrusy | 1.75 | 10 | 4.50 |
| 10/30/18 | Mealy | 2.00 | 10 | 5.99 |
+----------+---------+------+----------+-----------+
What I need the output to look like:
+----------+----------+--------------------+----------+--------------------+
| UniqueID | Date1 | New Price on Date1 | Date2 | New Price on Date2 |
+----------+----------+--------------------+----------+--------------------+
| 1 | 09/10/18 | 1.90 | 10/20/18 | 3.90 |
| 2 | 09/18/18 | 2.50 | 10/25/18 | 4.50 |
| 3 | 10/01/18 | 2.99 | 10/30/18 | 5.99 |
+----------+----------+--------------------+----------+--------------------+
I need to first convert table1.fruit to the representation of table2.fruit (apples-->savory, oranges-->citrusy, bananas-->mealy) then join on table1.fruit = table2.fruit, table1.duration = table2.duration, table1.cost = table2.cost, table1.date1 = table2.date1, and table1.date2 = table2.date1.
I don't know where to start on writing the statement. I looked over some previous questions posted here, but they really just go over the basics of linking two tables from different databases. Do I convert the table1.fruit first in the select statement, then join, or do I convert table1.fruit in the join statement? How do I join table2.date1 on both table1.date1 and table1.date2 to get the price associated with both dates?
If I can provide any more information for you, please let me know.
I am on SQL Server 2017 using Management Studio.
Thanks for any help in advance!
Create a mapping table to bridge between the different codes for fruits.
IF OBJECT_ID('tempdb..#FruitMappings') IS NOT NULL
DROP TABLE #FruitMappings
CREATE TABLE #FruitMappings (
Table1Fruit VARCHAR(100),
Table2Fruit VARCHAR(100))
INSERT INTO #FruitMappings (
Table1Fruit,
Table2Fruit)
VALUES
('Apples', 'Savory'),
('Oranges', 'Citrusy'),
('Bananas', 'Mealy')
SELECT
T1.*
--, whichever columns you need
FROM
Database1.Schema1.Table1 AS T1
INNER JOIN #FruitMappings AS F ON T1.Fruit = F.Table1Fruit
INNER JOIN Database2.Schema2.Table2 AS T2 ON
F.Table2Fruit = T2.Fruit AND
T1.Cost = T2.Cost AND
T1.Duration = T2.Duration
-- AND any other matches you need
You can use LEFT JOIN or even FULL JOIN, depending if you might have some fruits on a table that aren't available on the other (careful with NULL values if FULL JOIN).
If both databases are on the same SQL Server instance and your SQL Server login has access to both databases you can just use the full form of the object names:
select * -- Whatever...
from Database1.dbo.Table1 t1
inner join Database2.dbo.Table2 t2
on t1,UniqueId = t2.UniqueId -- Or whatever your join condition is
(adding where etc. clauses as required.)
This assumes both databases are using the default schema, otherwise replace dbo as necessary.
If the databases are on different servers you can use linked servers, but there are performance implications (the whole remote table may be read because the optimiser can't do much to filter it).

Using a table to lookup multiple IDs on one row

I have two tables I am using at work to help me gain experience in writing SQL queries. One table contains a list of Applications and has three columns -
Application_Name, Application_Contact_ID and Business_Contact_ID. I then have a separate table called Contacts with two columns - Contact_ID and Contact_Name. I am trying to write a query that will list the Application_Name and Contact_Name for both the Applications_Contact_ID and Business_Contact_ID columns instead of the ID number itself.
I understand I need to JOIN the two tables but I haven't quite figured out how to formulate the correct statement. Help Please!
APPLICATIONS TABLE:
+------------------+------------------------+---------------------+
| Application_Name | Application_Contact_ID | Business_Contact_ID |
+------------------+------------------------+---------------------+
| Adobe | 23 | 23 |
| Word | 52 | 14 |
| NotePad++ | 44 | 989 |
+------------------+------------------------+---------------------+
CONTACTS TABLE:
+------------+--------------+
| Contact_ID | Contact_Name |
+------------+--------------+
| 23 | Tim |
| 52 | John |
| 14 | Jen |
| 44 | Carl |
| 989 | Sam |
+------------+--------------+
What I am trying to get is:
+------------------+--------------------------+-----------------------+
| Application_Name | Application_Contact_Name | Business_Contact_Name |
+------------------+--------------------------+-----------------------+
| Adobe | Tim | Tim |
| Word | John | Jen |
| NotePad++ | Carl | Sam |
+------------------+--------------------------+-----------------------+
I've tried the below but it is only returning the name for one of the columns:
SELECT Application_Name, Application_Contact_ID, Business_Contact_ID, Contact_Name
FROM Applications
JOIN Contact ON Contact_ID = Application_Contact_ID
This is a pretty critical and 101 part of SQL. Consider reading this other answer on a different question, which explains the joins in more depth. The trick to your query, is that you have to join the CONTACTS table twice, which is a bit hard to visualize, because you have to go there for both the application_contact_id and business_contact_id.
There are many flavors of joins (INNER, LEFT, RIGHT, etc.), which you'll want to familiarize yourself with for the future reference. Consider reading this article at the very least: https://www.techonthenet.com/sql_server/joins.php.
SELECT t1.application_name Application_Name,
t2.contact_name Application_Contact_name,
t3.contact_name Business_Contact_name
FROM applications t1
INNER JOIN contacts ON t2 t1.Application_Contact_ID = t2.contact_id -- join contacts for appName
INNER JOIN contacts ON t3 t1.business_Contact_ID = t3.contact_id; -- join contacts for busName

considering using Cross Apply but not sure

This is my first question on stackoverflow and am looking forward to everyone's feedback and solutions.
I would put my current SQL skills at the lower end of intermediate.
Simple one for most of you: I need to write a query in an oracle SQL environment that returns all transactions after the active employees departure date.
Table looks like this:
| Name | dept | departure date |
| John | Sales | 3.12.2014 |
| David | IT | 7.27.2014 |
| Gary | Audit | 12.5.2013 |
Transaction table
| TransID | Emp Name | Amount | TransDate |
| 1 | John | 25.00 | 3.31.2014 |
| 2 | David | 30.00 | 8.13.204 |
| 3 | Gary | 15.00 | 1.1.2014 |
I'm trying to avoid a UNION ALL since the table has over 100+ employee records. On researching the use of CROSS APPLY it seemed like it could fit the situation. Any ideas are appreciated. Thanks!
Josh
You can just use a join:
select t.*
from employees e join
transactions t
on e.emp = t.emp and e.date < t.transdate;
You could write this using apply, but I think a join makes the intention more clear.