Can anyone explain this Query? - sql

with a as (
select a.*, row_number() over (partition by department order by attributeID) rn
from attributes a),
e as (
select employeeId, department, attribute1, 1 rn from employees union all
select employeeId, department, attribute2, 2 rn from employees union all
select employeeId, department, attribute3, 3 rn from employees
)
select e.employeeId, a.attributeid, e.department, a.attribute, a.meaning,
e.attribute1 as value
from e join a on a.department=e.department and a.rn=e.rn
order by e.employeeId, a.attributeid
this query is written by Ponder Stibbons for the answer of this question. But i am too dizzy with it as i quite don't understand what is going on here. i am new to SQL . so i would appreciate if anyone can explain what is happening on this query . thank you

Basically he unpivots the data using 3 select statements (1 for each attribute) and UNION them together to make a common table expression so that he gets rows for each employees attribute.
select employeeId, department, attribute1, 1 rn from employees union all
select employeeId, department, attribute2, 2 rn from employees union all
select employeeId, department, attribute3, 3 rn from employees
The other table he using a window function to assign a number to attribute, department. He uses this number later to join back to his unpivoted data. He posted his code for the example.
select a.*, row_number() over (partition by department order by attributeID) rn
from attributes a
I would suggest you use his example data he provided and run the following. This will show you the CTEs. I think once you see that data it will make more sense.
with a as (
select a.*, row_number() over (partition by department order by attributeID) rn
from attributes a),
e as (
select employeeId, department, attribute1, 1 rn from employees union all
select employeeId, department, attribute2, 2 rn from employees union all
select employeeId, department, attribute3, 3 rn from employees
)
SELECT * from a
SELECT * from e

Related

SQL Server Group Records Based Another Columns

I am working on a table that contains employee data. The table has historical employee records based on department and year as follows:
Now I want to consolidate records based on EmployeeId, Department and get the Min FromYear and Max ToYear like this:
I tried to use a query :
Select EmployeeId, Department, MIN(FromYear), MAX(ToYear)
from Employee
GROUP BY EmployeeId, Department
But this query fails for the employee with ID 3 as it returns me only 2 rows:
I have added a similar structure and query here: http://sqlfiddle.com/#!9/6f1e53/5
Any help would be highly appreciated!
This is a gaps-and-islands problem. Identify the islands using lag() and a cumulative sum. Then aggregate:
select employeeid, department, min(fromyear), max(toyear)
from (select e.*,
sum(case when prev_toyear >= fromyear - 1 then 0 else 1 end) over (partition by employeeid order by fromyear) as grp
from (select e.*,
lag(toyear) over (partition by employeeid, department order by fromyear) as prev_toyear
from employee e
) e
) e
group by employeeid, department, grp
order by employeeid, min(fromyear);
Here is a db<>fiddle.
you can use self join as well
select a.employeeid, min(a.fromyear), max(b.toyear) from emp a
inner join emp b on a.employeeid=b.employeeid
group by a.employeeid

Select only one employee from every department

I want one employee from every department (EmpDepartment), for example in my table there are:
3 employees with EmpDepartment 1
2 employees with EmpDepartment 2 and
1 Employee with EmpDepartment 3
I want EmployeeId, EmployeeName and EmpDepartment of any one employee from each separate department.
Use a windowing function like this:
SELECT *
FROM (
SELECT
E.*,
ROW_NUMBER() OVER (PARTITION BY EmpDepartment) AS RN
FROM Employee
) X
WHERE X.RN = 1
You can add an order clause the the windowing function if you have a business rule that you want to use in picking the employee
eg
ROW_NUMBER() OVER (PARTITION BY EmpDepartment order by EmployeeId) AS RN
This will get a random employee from each department due to ordering by NEWID()...
SELECT * FROM
(
SELECT EmployeeID, EmployeeName, EmployeeEmail
, ROW_NUMBER() OVER (PARTITION BY EmpDepartment ORDER BY NEWID()) AS rn
FROM dbo.Employee
) x
WHERE x.rn = 1
You can change the order by clause to something else if you want to.
This will return the employee from each department having the minimum EmployeeID in that department (since it is not important which employee will be in the results):
SELECT e.* FROM Employee e
WHERE NOT EXISTS (
SELECT 1 FROM Employee
WHERE EmpDepartment = e.EmpDepartment AND EmployeeID < e.EmployeeID
)
SELECT Top(1) EmployeeID, EmployeeName, EMPDeptartment FROM Employee WHERE EmpDetpartment = 1
UNION
SELECT Top(1) EmployeeID, EmployeeName, EMPDeptartment FROM Employee WHERE EmpDetpartment = 2
UNION
SELECT Top(1) EmployeeID, EmployeeName, EMPDeptartment FROM Employee WHERE EmpDetpartment = 3
You can either use rownumber to find any employee of a particular dept change rn to any value as 1,2,...etc
Select department, employee
from (
Select department, employee,
row_number() over (partition by department order by employee) rn
)
where rn =1;
or use simple group by
Select department, max(employee)
from table
group by department

SQL oracle: Need to display a query.

so i have 3 tables linked together named office, employee, and dependent.
office: Oid (PK), officeName
employee: EID(PK), Fname, Lname, JobTitle, Salary, DOH, Gender, DOB, OID(FK1), Supervisor(FK2)
Dependent: DID(PK), Fname, Lname, Gender, EID(FK1)
Here is the link to the picture of the tables:
http://classweb2.mccombs.utexas.edu/mis325/class/hw/hw12a.jpg
I need to display concatenated name and EID of 5 employees with the largest number of dependents, if there is a tie for the five largest, then I need to display all of the tying employees.
I am confused on how to begin. please help :)
thank you in advance
Just break down the problem:
How many dependents an EID has:
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
Add a rank
SELECT EID, C, RANK() OVER (ORDER BY C DESC)
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
We want the first 5
SELECT EID
FROM (
SELECT EID, C, RANK() OVER (ORDER BY C DESC) AS R
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
) S2
WHERE R <= 5
Now ask for what you want:
SELECT * -- or whatever
FROM Employee
WHERE EID IN (
SELECT EID
FROM (
SELECT EID, C, RANK() OVER (ORDER BY C DESC) AS R
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
) S2
WHERE R <=5
) S3
I suggest you run each step and make sure it gives you the expected results.
Ummm I would try something like this:
Select TOP 5
a.FNAME,
a.LNAME,
a.EID,
Count(b.EID) as Dependents
FROM employee a
LEFT JOIN dependent b on a.EID = b.EID
group by 1,2,3 order by Dependents desc

Top 2 Salary Grouped By Department

Below is the table I am referring to.
I want to find ou the 2 Employees in each department with highest salary.
Further to the above answer, if there are ties (multiple employees sharing the same salary), you can use the following to bring them all through instead of just picking two at random (which is what the ROW_NUMBER clause will do)
SELECT *
FROM (
SELECT *, DENSE_RANK() OVER (PARTITION BY Dept ORDER BY Salary DESC) AS rn
FROM MyTable ) t
WHERE t.rn <= 2
Use ROW_NUMBER() to get the top salaries per Department, then select the first two records from each departmental partiton:
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Dept ORDER BY Salary DESC) AS rn
FROM MyTable ) t
WHERE t.rn <= 2

Running Order by on column alias

I am trying to run following SQL query on northwind database :
SELECT * FROM (
SELECT DISTINCT ROW_NUMBER() OVER (ORDER BY Joinning DESC) rownum,
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) r
It's giving me the error :
Invalid column name 'Joinning'.
The 'rownumber' is required for pagination.
Can anybody please suggest how I can sort on the Joining alias with the rownumber generated ?
--A possible work around
Just figured out a work around; please suggest if anything is wrong or need changes :
SELECT ROW_NUMBER() OVER (ORDER BY Joinning DESC) rownum,* FROM (
SELECT
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) r
--To put further where clause on row number(what I wanted to do for pagination):
With myres as(
SELECT ROW_NUMBER() OVER (ORDER BY Joinning DESC) rownum,* FROM (
SELECT
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) a
) Select * from myres where myres.rownum > 0 and myres.rownum < = 0+20
Try
SELECT * FROM (
SELECT DISTINCT ROW_NUMBER() OVER (ORDER BY HireDate DESC) rownum,
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) r
Hope you ahve joinning in your table.
The order by clause is usually given at the last of the query like this :
SELECT * FROM (
SELECT DISTINCT ROW_NUMBER() rownum,
LastName, Country, HireDate AS Joinning)
FROM Employees
WHERE Region IS NOT NULL ORDER BY Joinning DESC)
Hope this helps you!
Use Original Name of the field, That will work just fine HireDate
SELECT * FROM (
SELECT DISTINCT ROW_NUMBER() OVER (ORDER BY HireDate DESC) rownum,
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) r