SQL to combine 2 tables - sql

I have 2 separate queries that returns to me the following tables:
===========================
Id f_name l_name
===========================
15 Little Timmy
16 John Doe
17 Baby Jessica
---------------------------
===========================
Id item_name item_price
===========================
15 Camera 100
15 Computer 200
16 Pony 55
---------------------------
In MySQL, how do I combine the 2 into this:
===================================================
Id f_name l_name item_name item_price
===================================================
15 Little Timmy Camera 100
15 Little Timmy Computer 200
16 John Doe Pony 55
17 Baby Jessica
---------------------------------------------------
Any assistance is greatly appreciated. Thanks.

select
name_table.Id,
name_table.f_name,
name_table.l_name,
item_table.item_name,
item_table.item_price
from
name_table
left join item_table
on name_table.Id = item_table.Id
Enjoy!

There are a lot of types of Joins, and it's a very interesting and important topic in database management. SO's own Jeff Atwood has a very good post describing the different types of joins and cases in which they would be used.

You need to use a left outer join:
SELECT names.Id, names.f_name, names.l_name, prices.item_name, prices.item_price
FROM names
LEFT OUTER JOIN prices
ON names.Id = prices.Id

If you want to perform this select statement regularly in your application, you might want to consider creating a view in the database. A view is basically a combination of data in more than one table. A major benefit of using a view here would be a simpler query in your app, so instead of doing the join in the app, you would simply select all the fields from the view.
Your CREATE VIEW statement would look more or less like Doug's answer, whilst your select would then be
select ID, f_name, l_name, item_name, item_price from my_view;
More details on MySQL CREATE VIEW

And if you want to to create a table with that result in database, do any of these selects/joins in a create table command.
CREATE TABLE foobar SELECT ...

Related

How to join 2 tables without common fields?

There are 2 tables:
Table 1: first_names
id | first_name
1 | Joey
7 | Ross
17| Chandler
Table 2: last_names
id | first_name
2 | Tribbiani
7 | Geller
25| Bing
Desired result:
id | full_name
1 | Joey Tribbiani
2 | Ross Geller
3 | Chandler Bing
Task:
Write the solution using only the simplest SQL syntax. Using store procedures, declaring variables, ROW_NUMBER(), RANK() functions are forbidden.
I have solution using ROW_NUMBER() function, but no ideas about solving this task using only the simplest SQL syntax.
P.S. I'm only trainee and it's my first question on stackoverflow
Simple join will suffice here
select * from first_names fn
join last_names ln on fn.id = ln.id - 1
But your question is very unclear though. Because join here is based rather on knowledge about Friends series rather than concrete logic...
You must create an id to join the tables.
This can be the order number in the table based in ids:
select
f.counter id, concat(f.first_name, ' ', l.last_name) full_name
from (
select t.*, (select count(*) from first_names where id < t.id) + 1 counter
from first_names t
) f inner join (
select t.*, (select count(*) from last_names where id < t.id) + 1 counter
from last_names t
) l
on l.counter = f.counter
See the demo.
Results:
> id | full_name
> -: | :-------------
> 1 | Joey Tribbiani
> 2 | Ross Geller
> 3 | Chandler Bing
Honestly, this is a stupid solution; it's vastly inefficient to ROW_NUMBER, and I wouldn't be surprised if LEAD is "not allowed" as ROW_NUMBER isn't. The fact that you were told to "use the simpliest SQL" means that the SQL you want to use is a subquery/CTE and ROW_NUMBER; that is as simple as this can really go. Anything else add a layer on unneeded complexity and will likely just make the query suffer from performance degradation. This one, for example, means you need to scan both tables twice; where as with ROW_NUMBER it would be once.
CREATE TABLE FirstNames (id int, FirstName varchar(10));
CREATE TABLE LastNames (id int, LastName varchar(10));
INSERT INTO FirstNames
VALUES(1,'Joey'),
(7,'Ross'),
(17,'Chandler');
INSERT INTO LastNames
VALUES (2,'Tribbiani'),
(7,'Geller'),
(25,'Bing');
GO
WITH CTE AS(
SELECT FN.id,
FN.FirstName,
LN.LastName
FROM FirstNames FN
LEFT JOIN LastNames LN ON FN.id = LN.id
UNION ALL
SELECT LN.id,
FN.FirstName,
LN.LastName
FROM LastNames LN
LEFT JOIN FirstNames FN ON LN.id = FN.id
WHERE FN.id IS NULL),
FullNames AS(
SELECT C.id,
C.FirstName,
ISNULL(C.LastName, LEAD(C.LastName) OVER (ORDER BY id)) AS LastName
FROM CTE C)
SELECT *
FROM FullNames FN
WHERE FN.FirstName IS NOT NULL
ORDER BY FN.id;
GO
DROP TABLE FirstNames;
DROP TABLE LastNames;
To answer the "Task" given:
"Task: Write the solution using only the simplest SQL syntax. Using store procedures, declaring variables, ROW_NUMBER(), RANK() functions are forbidden."
My answer would be the below?
"Why is this a requirement? SQL Server has supported ROW_NUMBER for 14 years, since SQL Server 2005. If you can't use ROW_NUMBER this infers you're using SQL Server 2000. This is actually a big security problem for the company, as 2000 has been out of support for close to a decade. Legislation like GDPR require a company to keep the technology they use secure, and it is very unlikely that this is therefore being met.
If this is the case, the solution if not the find a way around using ROW_NUMBER but to get the company back up to do date. The latest version of SQL Server that you can upgrade to from SQL Server 2000 is 2008; which also runs out of support on July 16 of this year. We'll need to get an instance up and running and get the existing features into this new server ASAP and get QA testing done as soon as possible. This needs to be the highest priority thing. After that we need to repeat the cycle to another version of SQL Server. The latest is 2017, which does support migration from 2008.
Once we've done that, we can then actually make use of ROW_NUMBER in the query; providing the simplest solution and also bringing the company back into a secure environment."
Sometimes requirements need to be challenged. From experience management can make some "stupid" requirements, because they don't understand the technology. When you're in an IT role, sometimes you will need to question those requirements and explain why the requirement isn't actually a good idea. Then, instead, you can aid Management to find the correct solution for the problem. At the end of the day, what they might be trying to fix could be an XY problem; and part of your troubleshooting will be to find out what X really is.

SQL Insert with value from different table

I have 2 tables storing information. For example:
Table 1 contains persons:
ID NAME CITY
1 BOB 1
2 JANE 1
3 FRED 2
The CITY is a id to a different table:
ID NAME
1 Amsterdam
2 London
The problem is that i want to insert data that i receive in the format:
ID NAME CITY
1 PETER Amsterdam
2 KEES London
3 FRED London
Given that the list of Cities is complete (i never receive a city that is not in my list) how can i insert the (new/received from outside)persons into the table with the right ID for the city?
Should i replace them before I try to insert them, or is there a performance friendly (i might have to insert thousands of lines at one) way to make the SQL do this for me?
The SQL server i'm using is Microsoft SQL Server 2012
First, load the data to be inserted into a table.
Then, you can just use a join:
insert into persons(id, name, city)
select st.id, st.name, c.d
from #StagingTable st left join
cities c
on st.city = c.name;
Note: The persons.id should probably be an identity column so it wouldn't be necessary to insert it.
insert into persons (ID,NAME,CITY) //you dont need to include ID if it is auto increment
values
(1,'BOB',(select Name from city where ID=1)) //another select query is getting Name from city table
if you want to add 1000 rows at a time that'd be great if you use stored procedure like this link

MS Access VBA: Combine 2 SQL statements with a LEFT JOIN

Hi all and thanks in advance for your help!
I am trying to use a JOIN to combine a fitlered SQL statement with a table in order to populate a combobox (makes sense?)
Here is the main SQL query:
MainSQLquery = "SELECT QuotationID, QuoteDate, EmployeeID FROM TestTable1"
I want to write a statement to use this with another table like so:
SELECT EmployeeID, EmployeeName
FROM MainSQLquery LEFT JOIN EmployeeTable
GROUP BY EmployeeID
But I can't get it right. I get a "Syntax error in FROM clause" even with something as simple as:
ComboSQL = "SELECT EmployeeID FROM " & MainSQLQuery
Me.Combo2.RowSource = ComboSQL
Do you guys know any way to do this?
*******BACKGROUND**********
For those of you who wants to see the bigger picture, I have a subform showing a list of quotations and based on a dynamic SQL statement, it is filetered with a WHERE clause based on different inputs and it looks like this when displayed:
QuoteID Quote date Employee ID
1 10/13 1
2 10/13 2
3 10/13 2
4 09/18 1
5 08/10 2
6 07/16 3
7 06/27 3
On the main form, I have comboboxes that I use to filter this subform, which works perfectly. But I also need my comboboxes to be filtered the same way as the subform content and without having any duplicate (that's the only thing I can't do right now).
So far I use the same filtered SQL query for the subform and all the comboboxes, so instead of having a neat Employee combobox that looks like this (with the example above):
1
2
3
I get that instead (same as the subform):
1
2
2
1
2
3
3
My idea is to have a main SQL query for the subform, and another SQLquery based on the main one for the comboboxes, something like that:
SELECT EmployeeID, EmployeeName
FROM MainSQLquery LEFT JOIN EmployeeTable
GROUP BY EmployeeID
if I could get this working, the filter would still be built in the mainSQL and I could group the EmployeeID field without problem.
I guess it should be fairly simple, but I can't get it right, there is something I don't know about using an SAL as source of another.
(I wish I could post pictures or a database sample, but a paranoid guy got my previous post deleted because of that, so it will have to do with text only, sorry about that)
When you have a JOIN you should have an ON to let the database know how to relate the tables:
SELECT EmployeeID, EmployeeName
FROM (
SELECT QuotationID, QuoteDate, EmployeeID
FROM TestTable1
) AS MainSQLquery LEFT JOIN EmployeeTable
ON MainSQLquery.EmployeeID = EmployeeTable.ID
GROUP BY EmployeeID
The LEFT JOIN gets all records from the table on the left of the join -- MainSQLquery -- and only the records from the right table -- EmployeeTable -- that match. If no matches are found in the right table, a NULL value is returned.
Given this example:
TestTable1
QuotationID | QuoteDate | EmployeeID
--------------------------------------------
1 10/1/2014 1
2 10/8/2014 2
3 10/5/2014 3
4 10/10/2014 1
5 10/20/2014 5
EmployeeTable
ID | EmployeeName
----------------------
1 Jeremy Smith
2 Pam Engles
3 Achim Flemmish
4 Sandra Hayes
This would be the result of the above query:
Result
EmployeeID | EmployeeName
--------------------------------
1 Jeremy Smith
2 Pam Engles
3 Achim Flemmish
5 NULL

How to add aggregate value to SELECT?

I'm selecting data from multiple tables and I also need to get maximum "timestamp" on those tables. I will need that to create custom cache control.
tbl_name tbl_surname
id | name id | surname
--------- ------------
0 | John 0 | Doe
1 | Jane 1 | Tully
... ...
I have following query:
SELECT name, surname FROM tbl_name, tbl_surname WHERE tbl_name.id = tbl_surname.id
and I need to add following info to result set:
SELECT MAX(ora_rowscn) FROM (SELECT ora_rowscn FROM tbl_name
UNION ALL
SELECT ora_rowscn FROM tbl_surname);
I was trying to use UNION but I get error - mixing group and not single group data - or something like that, I know why I cannot use the union.
I don't want to split this into 2 calls, because I need the timestamp of the current snapshot I took from DB for my cache management. And between select and the call for MAX the DB could change.
Here is result I want:
John | Doe | 123456
Jane | Tully | 123456
where 123456 is approximate time of last change (insert, update, delete) of tables tbl_name and tbl_surname.
I have read only access to DB, so I cannot create triggers, stored procedures, extra tables etc...
Thanks for any suggestions.
EDIT: The value *ora_rowscn* is assigned per block of rows. So in one table this value can differ per row. I need the maximal value from both (all) tables involved in query.
Try:
SELECT name,
surname,
max(greatest(tbl_name.ora_rowscn, tbl_surname.ora_rowscn)) over () as max_rowscn
FROM tbl_name, tbl_surname
WHERE tbl_name.id = tbl_surname.id
There's no need to aggregate here - just include both ora_rowscn values in your query and take the max:
SELECT
n.name,
n.ora_rowscn as n_ora_rowscn,
s.surname,
s.ora_rowscn as s_ora_rowscn,
greatest(n.ora_rowscn, s.ora_rowscn) as last_ora_rowscn
FROM tbl_name n
join tbl_surname s on n.id = s.id
BTW, I've replaced your old-style joins with ANSI style - better readable, IMHO.

Inner Join versus Exists() while avoiding duplicate rows

This is a complicated question so bear with me as I set up the scenario:
Say we have a simplified table setup like so:
table 1(employee): {
employee_id, -primary key
first_name,
last_name,
days_of_employment
}
with data:
employee_id first_name last_name days_of_employment
111 Jack Stevens 543
222 Clarice Bobber 323
333 Roy Cook 736
444 Fred Roberts 1000
...
table 2(teams): {
team_code, --primary key
description
}
with data:
team_code description
ERA Enrollment Records Assoc.
RR Rolling Runners
FR French Revolution
...
table 3(employees_teams):{
employee_id, --primary key
team_code --primary key
}
with data:
employee_id team_code
111 RR
111 FR
222 FR
222 ERA
333 FR
...
I'm hoping these tables should be clear as to what they are and their purpose. Here is my scenario from requirements: "I want the average days of employment of employees on the Rolling Runners and Enrollment Records Assoc. team." There are two ways I know how to write this query and they both seem to work well enough, but what I really want to know is which one is faster for the oracle database to process. Keep in mind that these queries are written the way they are to keep from producing duplicate rows which would screw up the average calculation:
Query 1:
SELECT AVG(e.days_of_employment) avg_days_of_employment
FROM employee e,
(
SELECT DISTINCT employee_id
FROM employees_teams
WHERE team_code IN ('ERA','RR')) available_employees
WHERE e.employee_id = available_employees.employee_id
Query 2:
SELECT AVG(e.days_of_employment) avg_days_of_employment
FROM employee e
WHERE EXISTS(
SELECT 1
FROM employees_teams et
WHERE et.team_code IN ('ERA','RR')
AND et.employee_id = e.employee_id)
It is possible that with this sample data I provided that this situation may not make sense to begin with, but I still would like to know which query is 'better' to use.
I would say go with the EXISTS approach since you are not really needing anything from the available_employees other than checking for the existence.
Having said that it depends on your data as well and how your database query optimizer optmizes it. I would suggest you to see the query plan for each approach and see which one is less expensive.
Check these links as well http://dotnetvj.blogspot.com/2009/07/why-we-should-use-exists-instead-of.html Can an INNER JOIN offer better performance than EXISTS