How to do sub-query correctly in Oracle?

Asked

Viewed 1,442 times

2

I need to do a sub-query of a table to find all employees who work in the same department that is part of São Paulo, but I’m not getting it. That is, I need to select from the three tables, departments, employees and locations to know from which locations the employees work. And I need to select state_province table locations while selecting the first_name, departments_id and job_id table employees.

I have the following tables :

Department table

DEPARTMENTS

department_id
department_name
location_id

Local table

LOCATIONS

location_id
street_address
postal_code
city
state_province
country_id

Table employed

EMPLOYEES

employee_id
first_name
last_name
email
phone_number
hire_date
job_id
department_id

With my current code it doesn’t work, this more or less like this :

SELECT firt_name, department_id, job_id 
FROM locations 
WHERE state_province = (SELECT * 
                        FROM locations 
                        WHERE state_province = 'Sao Paulo');

He starts to screw up the part about WHERE since state_province only belongs to the table LOCATIONS and there is no way for me to access its attributes. How can I do this sub-query correctly ?

I’m new to this part of select nestled with another select, so forgive me the grotesque errors.

  • replaces the * of the subquery by state_province, otherwise you would be equating a field with a whole record, since locations has more than one column

  • Thank you, but the problem now is that I can not select the attributes of the department table while nesting with the other select. I would need to show the employee name for example, which is in the departments table, while selecting state_province, from the Locations table. How can I do this ?

  • 1

    opa, sorry for the comment crossed in the reflection, it is the sleep and the hurry, I should have been quiet, haha =( I am writing an answer

1 answer

2


It is always good to think twice before using a subquery to solve an SQL problem, especially if it is something that handles large volumes of data or that is executed many times, because these queries have to be saved in memory for further comparison, worsening the performance of the application.

In the present case, considering that a EMPLOYEE is related to a DEPARTMENT and this to a LOCATION, you need to express this relationship in your query and I believe that it is not necessary to use Queries. There are two basic ways to do this with a single query, one defining clauses JOIN and other using tests in the clause WHERE leading to the creation of a INNER JOIN implicit.

In both cases all three tables must be involved and the fields must be qualified by the names of the tables to which they belong, to avoid ambiguity. It is possible to define aliases for tables, if necessary, to reduce the amount of text in the query, but I will keep the full names for clarity.


Using the clasp WHERE:

SELECT 
  employees.first_name, 
  employees.department_id, 
  employees.job_id 
FROM 
  employees,
  locations,
  departments
WHERE 
  departments.location_id = locations.location_id and
  employees.department_id = departments.department_id and 
  locations.state_province = 'sao paulo';

This type of query, in my opinion, has less "verbosity" than using JOIN explicit, making it easier to read. The use of WHERE for this type of purpose is only possible because it is a simple relationship, in which all tables have data to cross, so that the expressed equalities result in a INNER JOIN implicit.


Using INNER JOIN:

As I said above, I prefer the use of WHERE in these cases because I find it more interesting to put all the rules in one place, but I believe that the "most correct" is to define the relationships between tables in the FROM, using clauses JOIN. Besides being the canonical use of SQL, the main advantage is the possibility of expressing more complex relationships.

It follows the same relationship as the previous query, now expressed with two INNER JOIN. I took the liberty of changing the requested fields in SELECT and the filter in WHERE to demonstrate that the columns of all tables are accessible (note, this is possible in either of the two Join methods described here).

SELECT 
  employees.first_name, 
  employees.department_id, 
  employees.job_id ,
  departments.department_name,
  locations.street_address
FROM 
  employees inner join departments on employees.department_id = departments.department_id
            inner join locations on departments.location_id = locations.location_id 
WHERE 
  departments.department_name = 'ti';

The explicit definition of JOIN enables faster visual understanding of the relationships established by the query. There are also other types of JOIN that give more control over which of the tables takes precedence in data recovery, something that is not at all possible through the use of WHERE.


Chaining:

If for any reason it is necessary that the relationship between the tables is not expressed in the clause FROM nor in the WHERE as above, it can be reproduced via chained queries (also called "derived queries") in the clause SELECT.

Although it is obtained, for all purposes, an "unfolding" of the use of WHERE previously demonstrated, this method is somewhat limited in the fields that can be searched, since only the columns of the query "outside" will be returned:

select * from employees where department_id in (
  select department_id from departments where location_id = (
    select location_id from locations where state_province = 'sao paulo'
  )
);

Note that it is possible to compare a field with a clause query WHERE, this query also needs to return only one field of the same type. If the subquery returns more than one registration and it is necessary to search for all, change the operator of the WHERE of = for in.


  • Hello friend, thank you for the reply full of information, but in the case even not feasible I need to use sub-query. And in this case, I need to select state_province from the Locations table while selecting first_name, departments_id and job_id from the Employees table.

  • Even the above query, without being JOIN, does not return me anything even if there is in the table Locations, an employee of São Paulo.

  • 1

    @By "need to use subquery" you mean you cannot change the from and Where of the main query? as to not working the data that I filled in the example are all in low box, but I saw by the question that your database contains "Sao Paulo" capitalized. Did you ever check that?

  • Yes I did check. I have to select the three tables, and find all the employees who work in the city São Paulo. And only using sub-query, without Join.

  • 1

    @Monteiro the chaining of queries that I included in the answer helps you?

  • Strange, seems to be all right the chaining but still does not return the query showing the city São Paulo and employees related to it.

  • 1

    @Monteiro he does not return you anything, as you also commented in the case of the use of WHERE up? When did you say the JOIN works, also tested with the field state_province = 'Sao Paulo'? If not, just try to see if it’s a problem, too. It may be that the Sao Paulo registry has something that makes the bank not find it, such as being surrounded by spaces. A test would also be to use the like instead of equality: where state_province like '%Sao Paulo%'...

  • It didn’t work the same way. So, I have only one employee who works in the city of São Paulo. But when I do the nested SELECT it returns me all employees of all cities. It looks something like this : SELECT first_name, department_id,job_id FROM Employees, Locations WHERE state_province = (SELECT state_province FROM Locations WHERE state_province = 'Sao Paulo'); And he ends up returning all employees instead of only the employee who actually works in São Paulo. How can I fix this?

  • This is because you have put two tables on WHERE. In practice you’re picking up all the records of EMPLOYEES and joining with all the records of LOCATIONS that has state_province = 'Sao Paulo'. You can’t skip steps like this, your data model has 3 chained relationships, Employees > departments > Locations. Look at the comparison in this fiddle: http://sqlfiddle.com/#! 4/49b40/18

  • Exactly, that’s why I’m having problems. I’m not only able to pull from the EMPLOYEES record, because it joins the LOCATIONS record part. In your fiddle comparison you gave what I wish was running on Oracle. How can I fix this once and for all? I have to go in pieces to take all 3 relationships and get the result only later?

Show 6 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.