sub-queries are running fast but joining them is taking forever - sql

I have two tables (sample below) with some additional columns that I have not shown here. The only way to join the two tables is by using a combination of first name, last name, and address.
table A (~3000 rows):
First Name
Last Name
Address
Jane
Doe
123 Main St
Jack
Jones
100 Chestnut St
Tom
Locke
50 Market St
table B (~ 9M rows):
First Name
Last Name
Address
Jane
Doe
123 Main St
Jack
Jones
100 Chestnut St
Jeremy
Thomas
27 Spruce St
I have tried the following code -
select * from
(select first_name, last_name, address, concat(first_name, last_name, address) as con_A
from table_A) as A
join
(select first_name, last_name, address, concat(first_name, last_name, address) as con_B
from table_B) as B
on A.con_A=B.con_B
The above code is a generalization of what my code looks like. I have tried to only put the columns I need in the sub queries in my original code.
The two sub queries run within seconds when I run them individually but taking over an hour to execute when I join them.

I don't know that I'd use inline tables for this ... why not just a direct join?
select
A.first_name,
A.last_name,
A.address
from
table_A A
join table_B B on A.first_name = B.first_name AND
A.last_name = B.last_name AND
A.address = B.address
Now this is an inner join, so you'll only get exact matches for both. If you want to show records from one table whether they match or not, you'll need to use an outer join (left or right depending on the table you want to drive the results).

Instead of using the sub query in join you can directly use the join for better performance of the query.
select A.first_name, A.last_name, A.address from
(select first_name, last_name, address from table_A) as A
join
(select first_name, last_name, address from table_B) as B
on A.first_name=B.first_name, A.last_name=B.last_name, A.address=B.address
And one more thing don't use normal join use either left or right join based on your need. If you joining 3k records with 9M records all combination will form in the result. It makes very cost effective operation.

Related

How can I create a BigQuery record with a join, but without specifying all fields?

Question: How to join tables using join clause without listing all the fields?
Data
Given two tables, Person and Address:
Person
name
address_id
Alice
10
Bob
11
Charlie
10
Address
id
street
city
10
William Street
NYC
11
Old Street
London
Desired result:
I'd like to join them with a record, like so:
name
address.street
address.city
Alice
William Street
NYC
Bob
Old Street
London
Charlie
William Street
NYC
However, I have many columns in both tables and I don't want to specify them all.
So something a bit like using EXCEPT but with the joined columns becoming nested in an address record:
SELECT * EXCEPT (address_id)
FROM person p
JOIN address a
ON p.address_id = a.id
Is this possible in BigQuery?
Consider below query:
SELECT p.* EXCEPT(address_id), (SELECT AS STRUCT a.* EXCEPT(id)) AS address
FROM Person p JOIN Address a ON p.address_id = a.id;
output:
You can join more tables with similar approach.
SELECT p.* EXCEPT(address_id),
(SELECT AS STRUCT a.* EXCEPT(id)) AS address,
(SELECT AS STRUCT j.* EXCEPT(name)) AS Job
FROM Person p
JOIN Address a ON p.address_id = a.id
JOIN Job j ON p.name = j.name;
output:

Querying SQL table a second time with info from the first

I am running a query against a PeopleSoft database, and am unsure whether it is possible to get information from the same table, based on the initial query, in a single call. For example, the table I am hitting returns EmployeeID, FullName, FirstName, LastName, Position_NBR, and ReportsTo. But the ReportsTo is in the form of the manager's Position_NBR (found in same table), and I would like to get it in the name format. I would like to do something like this, but not sure if it is possible:
SELECT Employee_ID, FullName, FirstName, LastName, Position_NBR
,(Select Name From Employee Where Position_NBR='12345') As Manager
From Employee
Where EmployeeID='8675309'
Is this even possible, or do I need to fully return the first piece before I can use the second?
Yes, you can refer to the first table and it's best to limit the result of the subquery to 1 result (just in case the employee has 2 o more managers)
SELECT Employee_ID, FullName, FirstName, LastName, Position_NBR
,(Select Top 1 E2.Name From Employee as E2 Where E2.Position_NBR=Employee.Position_NBR) As Manager
From Employee
Where EmployeeID='8675309'
(T-SQL Syntax)
You should be able to do this by linking fields.
Here are some examples using the Oracle Database:
e.g.
SELECT
table1.Employee_ID, table1.Name, table1.Boss_ID
,(select table2.name from Employee table2 where table1.Boss_ID = table2.Employee_ID) As Manager
From
Employee table1
Where
table1.Employee_ID='333'
/
Alternately, try a SQL JOIN.
SELECT
table1.Employee_ID, table1.Name, table1.Boss_ID
,table2.Name As Manager
From
Employee table1
inner join Employee table2
on table1.Boss_ID = table2.Employee_ID
Where
table1.Employee_ID='333'
/
Here is a link to a working example with some fake data:
http://sqlfiddle.com/#!4/210580/7

Finding couples of occurrences - Postgresql

I need to find possible couplings of employees and department that they worked for. I need to include only the couplings of 2 different departments, so if an employee worked for more than 2 departments, I need to divide them into couplings of 2 departments to show the transfers. Also the period of the contract of the employee at the first department must be earlier than the contract at the second department. I need to list the values as "first_name", "last_name, "deptnr1", "dept1", "deptnr2", "dept2".
For example John Doe worked for department A(deptnr 9) from 01/01/2016 to 06/06/2016 and for department B(deptnr 3) from 10/06/2016 to 12/12/2017, the result should be like :
John, Doe, 9, A, 3, B
If he then returned to his job at department A, there should be another coupling like this to make his 2nd transfer visible:
John, Doe, 3, B, 9, A
so if he transfers around, we should have as many couplings of departments as possible, in this case 2 transfers, thus 2 couplings out of 3 departments(A => B => A so A,B/B,A).
I have 4 tables.
Person (PK email, first_name, last_name, FK postcode, FK place_name)
Employee(PK employeenr, FK email)
Department(PK departmentnr, name, FK postcode, FK place_name)
Contract(PK periode_begin, PK periode_end, FK departmentnr, FK employeenr)
I have tried this but I don't know how to make use of aliases to take values from let's say department.name and put them on other columns as name1 and name2. Also I couldn't figure out a way to make couplings out of let's say four transfers like (A=> B=> C=> D=> E TO A,B/B,C/C,D/D,E).
SELECT
first_name,
last_name,
d1.departmentnr AS deptnr1,
d1.name AS dept1,
d2.departmentnr AS deptnr2,
d2.name AS dept2,
FROM person
INNER JOIN employee ON employee.email=person.email
INNER JOIN contract ON contract.employeenr = employee.employeenr
INNER JOIN department d1 ON department.departmentnr = contract.departmentnr
where contract.employeenr in
(SELECT employeenr FROM contract
GROUP BY employeenr HAVING COUNT(employeenr)>1
AND COUNT(employeenr)>1)
Use the window function lead()
select
first_name,
last_name,
deptnr1,
dept1,
deptnr2,
dept2
from (
select
first_name,
last_name,
departmentnr as deptnr1,
name as dept1,
lead(departmentnr) over w as deptnr2,
lead(name) over w as dept2,
periode_begin
from person p
join employee e using(email)
join contract c using(employeenr)
join department d using(departmentnr)
window w as (partition by email order by periode_begin)
) s
where deptnr2 is not null
order by first_name, last_name, periode_begin
Read also about window functions in the documentation.

Querying from two tables in Oracle Database

I have two tables where I have students details and other table consists of the details of TAs. Tables are as follows:
Students(B#, first_name, last_name, status, GPA, email, bdate, dept)
TAs(B#, ta_level, office)
Now, For each TA from the CS department, find his/her B#, first name, last name, and birth date. I have tried the following query:
select Students.B#, Students.FIRST_NAME, Students.LAST_NAME, Students.BDATE
from Students INNER JOIN TAs ON Students.B# = TAs.B#;
but I have to get only those TAs who are studying in Computer Science. I am using Oracle DB. How will I add another condition after inner join?
For each TA from the CS department
Is there a table or a column specify if a student is studying Computer Science ? however as per your question it seems from the department you can know that.
You can do the below:
select Students.B#, Students.FIRST_NAME, Students.LAST_NAME, Students.BDATE
from Students INNER JOIN TAs ON Students.B# = TAs.B#
where Students.dept='CS' -- or computer science depending on the value.

SQL Server : replace several instances of userID with username

I may be overthinking this but I have not managed to figure it out or find a solution, so I'm hoping for a pointer in the right direction. I tried using the Select ColumnA AS Column B etc but it's not doing what I want.
I have 2 tables, scenario examples below
Table 1 (Vehicle)
VehicleID (001)
VehicleMake (Ford)
VehicleModel (Falcon)
VehicleExCleanEmpID (005)
VehicleIntCleanEmpID (003)
Table 2 (Employee)
EmpID (005)
EmpName (Dave)
The scenario being that a vehicle is cleaned internally or externally by any one of a pool of employees shown by the relevant ID in the Vehicles table.
I want to show in a query VehicleID, InsideCleanName, ExternalCleanName rather than showing the employee's ID.
So end up with results similar to this
VehicleID InsideCleanName ExternalCleanName
------------------------------------------------
001 Bob Dave
002 Sue Dave
003 John Sid
Thanks for any tips and or help
THat seems like a pretty simple query with two inner joins to the Employee table - something like this:
SELECT
v.VehicleId,
InsideCleanName = e1.EmpName,
ExternalCleanName = e2.EmpName
FROM
dbo.Vehicle v
INNER JOIN
dbo.Employee e1 ON v.VehicleIntCleanEmpId = e1.EmpID
INNER JOIN
dbo.Employee e2 ON v.VehicleExCleanEmpId = e2.EmpID
Joining to the Employee e1 table is giving you the employee who was responsible for the inside cleaning, while joining a second time, to Employee e2 gives you the one responsible for the external cleaning.
Join the two table with EmpId and select the columns you want similar to the code below:
select column1, column2 from table1 inner join table2 on table1.EmpId = table2.EmpId