single row subquery issue - sql

I am using the following query:
select P.job_ref, P.emp_num, P.name,
P.job_title , P.job_type,
P.dept_ref, P.dept, J.mgr_rept,
(select P.name as manager_name
from PEOPLE P, JOB J
where J.mgr_rept=P.job_ref)
from PEOPLE P, JOB J
where P.job_ref=J.job_ref
The issue is the manager and employee names reside in the same table under name. job_ref correlates to mgr_rept in the job table. An employees job_ref would equal a value in the job table that would pull up job information. The manager name however lies in the people table. The mgr_rept value would be the managers job_ref number. Using this query returns more than one row so I'm looking for some help please.
Thank you

First of all, you should no longer use the old comma-separated join syntax. It has been replaced in standard SQL with explicit joins more than 20 years ago.
Your subquery selects all people. It is not linked anyway to the record in the main query. Maybe you confused yourself by using the same table aliases again. It should be about this instead:
select
P.job_ref, P.emp_num, P.name,
P.job_title , P.job_type,
P.dept_ref, P.dept, J.mgr_rept,
(
select mgr.name
from PEOPLE mgr
where mgr.job_ref = J.mgr_rept
) as manager_name
from PEOPLE P
join JOB J on P.job_ref = J.job_ref;
I'm not 100% sure however, because I don't understand your table structure completely. This only works if job_ref is unique in table people.

Related

When using JOIN feature in Oracle, I have some question about when I am using extra ALIAS in this code

Before start, Sorry some of results and datas are written in Korean.
Here is a code that I currently am looking on.
SELECT S.*, D.DNAME
FROM STUDENT S, DEPARTMENT D
WHERE (SUBSTR(S.JUMIN,7,1),S.WEIGHT) IN (SELECT SUBSTR(JUMIN,7,1),MAX(WEIGHT)
FROM STUDENT GROUP BY SUBSTR(JUMIN,7,1))
AND S.DEPTNO1 = D.DEPTNO;
And here is the DEPARTMENT data.
And this is the STUDENT data.
I got a result as I want. But I have some questions when I change this part of the code
WHERE (SUBSTR(S.JUMIN,7,1),S.WEIGHT) IN (SELECT SUBSTR(JUMIN,7,1),MAX(WEIGHT)
into this one
WHERE (SUBSTR(S.JUMIN,7,1),S.WEIGHT) IN (SELECT
S.SUBSTR(JUMIN,7,1),MAX(S.WEIGHT)
What I do is simply put S infront of JUMIN and WEIGHT in line3.
But when I do this it shows me the whole data.
I thought JOIN ALIAS (which are S,D in this code) is used as way show that I have two tables to use that is labeled with S and D. S means this data is in STUDENT and D is in DEPARTMENT.
But I think I get it in a wrong way.
Anyway I have no idea how this result is come out.
This one is referring to your main table not the subquery table.
WHERE (SUBSTR(S.JUMIN,7,1),S.WEIGHT) IN (SELECT
S.SUBSTR(JUMIN,7,1),MAX(S.WEIGHT)
Your original query is already correct. In which you already have a new result set based on your aggregation.
WHERE (SUBSTR(S.JUMIN,7,1),S.WEIGHT) IN (SELECT SUBSTR(JUMIN,7,1),MAX(WEIGHT)

Which Oracle query is faster

I am trying to display employee properties using C# WPF view.
I have data in '2' different oracle tables in my database:
Those tables structure at high-level is...
Employee table (EMP) - columns:
ID, Name, Organisation
Employee properties table (EMPPR) - columns
ID, PropertyName, PropertyValue
The user will input 'List of Employee Name' and I need to display Employee properties using data in those '2' tables.
Each employee has properties from 40-80 i.e. 40-80 rows per employee in EMPPR table. In this case, which approach is more efficient?
Approach #1 - single query data retrieval:
SELECT Pr.PropertyName, Pr.PropertyValue
FROM EMP Emp, EMPPR Pr
WHERE Emp.ID = Pr.ID
AND Emp.Name IN (<List of Names entered>)
Approach #2 - get IDs list using one query and Get properties using that ID in the second query
Query #1:
SELECT ID
FROM EMP
WHERE Name IN (<List of Names entered>)
Query #2:
SELECT PropertyName, PropertyValue
FROM EMPPR
WHERE ID IN (<List of IDs got from Query#1>)
I need to retrieve ~10K employee details at once where each employee has 40-80 properties.
Which approach is good?
Which query is faster?
The first one, which uses a single query to fetch your results.
Why? much of the elapsed time handling queries, especially ones with modestly sized rows like yours, is consumed going back and forth from the client to the database server.
Plus, the construct WHERE something IN (val, val, val, val ... ... val) can throw an error when you have too many values. So the first query is more robust.
Pro tip: Come on into the 21st century and use the new JOIN syntax.
SELECT Pr.PropertyName, Pr.PropertyValue
FROM EMP Emp
JOIN EMPPR Pr ON Emp.ID = Pr.ID
WHERE Emp.Name IN (<List of Names Inputted>)
Use first approach of join between two tables which is far better than using where clause two times.

Ms-Access: counting from 2 tables

I have two tables in a Database
and
I need to retrieve the number of staff per manager in the following format
I've been trying to adapt an answer to another question
SELECT bankNo AS "Bank Number",
COUNT (*) AS "Total Branches"
FROM BankBranch
GROUP BY bankNo
As
SELECT COUNT (*) AS StaffCount ,
Employee.Name AS Name
FROM Employee, Stafflink
GROUP BY Name
As I look at the Group BY I'm thinking I should be grouping by The ManID in the Stafflink Table.
My output with this query looks like this
So it is counting correctly but as you can see it's far off the output I need to get.
Any advice would be appreciated.
You need to join the Employee and Stafflink tables. It appears that your FROM clause should look like this:
FROM Employee INNER JOIN StaffLink ON Employee.ID = StaffLink.ManID
You have to join the Eployee table twice to get the summary of employees under manager
select count(*) as StaffCount,Manager.Name
from Employee join Stafflink on employee.Id = StaffLink.EmpId
join Employee as Manager on StaffLink.ManId = Manager.Id
Group by Manager.Name
The answers that advise you on how to join are correct, assuming that you want to learn how to use SQL in MS Access. But there is a way to accomplish the same thing using the ACCESS GUI for designing queries, and this involves a shorter learning curve than learning SQL.
The key to using the GUI when more than one table is involved is to realize that you have to define the relationships between tables in the relationship manager. Once you do that, designing the query you are after is a piece of cake, just point and click.
The tricky thing in your case is that there are two relationships between the two tables. One relationship links EmpId to ID and the other links ManId to ID.
If, however, you want to learn SQL, then this shortcut will be a digression.
If you don't specify a join between the tables, a so called Cartesian product will be built, i.e., each record from one table will be paired with every record from the other table. If you have 7 records in one table and 10 in the other you will get 70 pairs (i.e. rows) before grouping. This explains why you are getting a count of 7 per manager name.
Besides joining the tables, I would suggest you to group on the manager id instead of the manager name. The manager id is known to be unique per manager, but not the name. This then requires you to either group on the name in addition, because the name is in the select list or to apply an aggregate function on the name. Each additional grouping slows down the query; therefore I prefer the aggregate function.
SELECT
COUNT(*) AS StaffCount,
FIRST(Manager.Name) AS ManagerName
FROM
Stafflink
INNER JOIN Employee AS Manager
ON StaffLink.ManId = Manager.Id
GROUP BY
StaffLink.ManId
I don't know if it makes a performance difference, but I prefer to group on StaffLink.ManId than on Employee.Id, since StaffLink is the main table here and Employee is just used as lookup table in this query.

SQL Maximum number of doctors in a department

my problem is this:
I have a table named
Doctor(id, name, department)
and another table named
department(id, name).
a Doctor is associated with a department (only one department, not more)
I have to do a query returning the department with the maximum number of doctors associated with it.
I am not sure how to proceed, I feel like I need to use a nested query but I just started and I'm really bad at this.
I think it should be something like this, but again I'm not really sure and I can't figure out what to put in the nested query:
SELECT department.id
FROM (SELECT FROM WHERE) , department d, doctor doc
WHERE doc.id = d.id
A common approach to the "Find ABC with the maximum number of XYZs" problem in SQL is as follows:
Query for a list of ABCs that includes each ABC's count of XYZs
Order the list in descending order according to the count of XYZs
Limit the result to a single item; that would be the top item that you need.
In your case, you can do it like this (I am assuming MySQL syntax for taking the top row):
SELECT *
FROM department dp
ORDER BY (SELECT COUNT(*) FROM doctor d WHERE d.department_id=dp.id) DESC
LIMIT 1
You can use Group BY
Select top (1) department.id,count(Doctor.*) as numberofDocs
from department inner join Doctor on Doctor.id = department.id
Group by department.id
Order by count(Doctor.*) desc
I generally avoid using sub queries in MySQL due to a well known bug in MySQL. Due to the bug, MySQL executes the inner query for every single outer query result. Therefore, if you have 10 departments, then doctor query would be executed 10 times. The bug may have been fixed in MySQL 5.6. In this particular case the number of departments may not be large, therefore performance may not be your main concern. However, the following solution should work for MySQL and much more optimized. The answer by dasblinkenlight is almost the same, just got ahead of me :). But MySQL does not support the command top.
select dep.id, dep.name, count(doc.id) as dep_group_count from Doctor doc join department dep on doc.department = dep.id group by doc.department order by dep_group_count DESC LIMIT 1

Why table exists two times under different aliases in FROM clause of SQL query?

I have this query:
SELECT to_number(gr.code) group_index,
gr.NAME group_name, f.*,
gr.description gr_desc
FROM obj$groups gr, obj$group_objects gro,
obj$group_objects gro2, tdf$flex_fields f,
inv$requests w, inv$Direction_Criterions c
WHERE gr.NO = gro.object_no
AND gro.group_no = obj$group_service.path_to_no(
'Some Condition String',
tdf$flex_field_service.get_local_list_group_no)
AND gro2.group_no = gr.NO
AND f.NO = gro2.object_no
AND w.no = 11593597
AND c.direction_no = w.direction_no
AND f.no = c.criterion_no
ORDER BY to_number(gr.code), f.name
Why are two same tables (group_objects) present here? I tried to reverse-engineer this, but couldn't myself, maybe anyone here already know of this trick?
This happens in Oracle database.
It's an operation called self-join. When you want to join records from the same table.
It usually happens when you have records related to records in the same table. Example:
create table tree
(
id number primary key,
parent_id number,
value varchar2(100)
);
So, if you want to retrieve nodes and their parents you would do:
select c.id, c.value, p.value as parent_value
from tree c inner join tree p on (c.parent_id = p.id)
Something similar is happening in the query you posted.
group_objects is being joined to groups in the clause gro2.group_no = gr.NO and to flex_fields in the clause f.NO = gro2.object_no. I suspect this covers the case where obe set of group object isn't exactly the same as the other set and this limits the rows in the two joins where one join removes a group_object that would then not be available to join to the other table.
It's hard to divine the original programmer's intent from this snippet, especially without a description of what the various tables hold.
However, it appears to me as if the final result of this query is supposed to report information from two different records from the group_objects table — one in which the group no matches "Some Condition String" and the other in which the group no matches a column value from the groups table. If I had to guess, it's retrieving an operation in which an item was transferred between two groups, or substituted to be used in place of an object from a second group, or something like that.
For illustration, the equivalent with the standard EMP table would be:
select e.ename, m.ename manager_name
from emp e, emp m
where m.empno = e.mgr;
Or in more modern syntax:
select e.ename, m.ename manager_name
from emp e
join emp m on m.empno = e.mgr;
i.e. show the names of employees with managers and the name of their managers.
The point is that the same table is used twice in the query in a different "role". It need not be a self-join, there could be another table (or more) in between like this:
select e.ename, pm.ename projmanager_name
from emp e
join project_assignments pa on p.empno = pa.empno
join projects p on p.proj_id = pa.proj_id
join emp pm on pm.empno = p.projmanager_empno;
i.e. show the names of employees assigned to projects and show the name of the project manager of that project.