Transfer row to column Oracle SQL - sql

Is below example good solution to get in one row all employee where job = 'MANAGER'
with cte as (
Select
job,
case when SAL = 2850 then ename end as SAL_1,
case when SAL = 2450 then ename end as SAL_2,
case when SAL = 2975 then ename end as SAL_3
from
(Select * from emp where job = 'MANAGER')
)
Select job,MIN(SAL_1) as SAL_1,MIN(SAL_2) as SAL_2,MIN(SAL_3) as SAL_3 from cte
group by job

No, this isn't a good way to show one row with all managers. Your query can only show up to three managers, and it doesn't even guarantee to show any manager at all. This depends on whether they happen to have one of the three salaries or not.
When writing a query you don't know how many managers there will be (and how much they earn) at the time someone runs the query. But in SQL queries you must state which (this includes "how many") columns to select.
Three options:
Just select rows (select * from emp where job = 'MANAGER') and let your app care about the display (i.e. loop through the rows and fill a grid with columns accordingly). This is the typical solution.
Count managers (select count(*) from emp where job = 'MANAGER'). Then build a separate query with as many columns as there are managers found and run this query. This technique is called "dynamic SQL". You can do this from your app or use Oracle's built-in programming language PL/SQL.
Put all the names into one column, i.e. have a string column that contains all names separated by comma, semicolon or whatever. Use LISTAGG for this.

Related

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.

Access SQL Can't Create Two Grouped Averages

Apologies for my simple problem, I am an absolute novice. I have the following code in separate queries
I am attempting to display 3 columns, the average male salary for a set job, average female salary for a set job and the JobID. Separately these queries work however I cannot work out how to combine them.
I have tried multiple solutions from this site for example trying to put multiple select statements inside
and also by using a 'union' solution however cannot get either to work.union This simply compiles them into a single column and sorts via salary not JobID.
SELECT Round(Avg(Salary)) AS AverageMaleSalary, JobID
FROM Employee WHERE Gender = "M"
GROUP BY JobID;
SELECT Round(Avg(Salary)) AS AverageFemaleSalary, JobID
FROM Employee WHERE Gender = "F"
GROUP BY JobID;
You could use conditional aggregation
SELECT JobId,ROUND(AVG(IIF(Gender='F', Salary, NULL))) AS AverageFemaleSalary
,ROUND(AVG(IIF(Gender='M', Salary, NULL))) AS AverageMaleSalary
FROM Employee
GROUP BY JobId;

SQL query from Lynda.com

I have a question about two queries. Will these two queries give the same result? I am trying to find the average salary by department:
Select s1.department, avg(s1.salary)
From
(Select department, salary
From staff
Where salary > 100000) s1
Group by s1.department
vs
select department, avg(salary) as avg_salary
from staff
where salary > 100000
group by department
Yes, it gives the same amounts back.
the bottom query gets data from a sub select which gets its data from the table, whereas the top query gets it straight from the table itself.
There are no additional filters in there. So the result will be the same.
you can test it out however, don't take my word for it.

What select is executed first in a nested subquery?

For such a subquery, what select is executed first?
SELECT name, salary, dept_id
FROM employee
WHERE salary >
( SELECT AVG(salary) FROM employee
WHERE dept_no =
( SELECT dept_no FROM employee
WHERE last_name =
( SELECT last_name FROM employee
WHERE salary > 50000))) ;
This: SELECT last_name FROM employee ?
SQL is a declarative language, not a procedural language. That is, the query does not specify the execution path, it specifies the logic for the result set. So, any of the queries could be "executed" first, depending on what the SQL optimizer decides to do.
That said, it is probably more important to understand the query logic than to understand how it is executed (at least at this stage). Your queries are all uncorrelated, so you can actually start with either the innermost or the outermost and work from there. Something like:
Get all employees whose salary
is greater than the average salary for the department
where employees with the same last name
have a salary greater than 50,000
Whether that is how the query is executed is immaterial. Something like that is what the query will return.

single row subquery issue

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.