How to find the oldest date in an SQL Table - sql

I'm making a SQL query and I need some help
The question is:
What is an employee's current salary , and what was their salary when they first started working?
(give name , first letters , current salary , department name , start date and their salary when they started)
The problem is:
I keep getting all the dates, and I can't find out how to filter it to only the first date (start/hire date) being shown.
Any suggestions?
My SQL code looks like this:
SELECT M.NAME,
M.FIRSTLETTERS,
M.MONTHSALARY,
D.NAME,
H.STARTDATE,
H.SALARY
FROM E_EMPLOYEES M
LEFT OUTER JOIN E_DEPARTMENTS A
ON M.AFD = A.ANR
INNER JOIN E_historie H
ON M.MNR = H.MNR

You can use aggregation and keep for this purpose. The query looks like:
SELECT M.NAME, M.FIRSTLETTERS,
MIN(H.STARTDATE) as STARTDATE,
MAX(H.SALARY) KEEP (DENSE_RANK FIRST ORDER BY H.STARTDATE) as FIRST_SALARY,
MAX(H.SALARY) KEEP (DENSE_RANK FIRST ORDER BY H.STARTDATE DESC) as LAST_SALARY
FROM E_EMPLOYEES M INNER JOIN
E_DEPARTMENTS A
ON M.AFD = A.ANR INNER JOIN
E_historie H
ON M.MNR = H.MNR
GROUP BY M.MNR, M.NAME, M.FIRSTLETTERS;

Use ROW_NUMBER to find the first salary of each employee from history table
SELECT M.NAME,
M.FIRSTLETTERS,
M.MONTHSALARY, -- considering this is current salary
A.NAME, -- I think there is a typo here Alias name should be A not H
H.STARTDATE,
H.SALARY
FROM E_EMPLOYEES M
LEFT OUTER JOIN E_DEPARTMENTS A
ON M.AFD = A.ANR
INNER JOIN (SELECT Row_number()OVER(partition BY H.MNR ORDER BY H.STARTDATE ASC) AS Rn,
H.MNR,
H.STARTDATE,
H.STARTDATE
FROM E_historie H) H
ON M.MNR = H.MNR
WHERE Rn = 1

Related

Get a column without adding it to the group by

select year, gender, max(nHospitalizations) from (select TO_CHAR(i.since, 'YYYY') as year, u.gender, h.name,count(h.name) as nHospitalizations from hospital h
join hospitalization i on i.hospital = h.name
join person u on i.person = u.numberID
group by TO_CHAR(i.since, 'YYYY'), u.gender, h.name)
group by year, gender
order by year desc, gender asc
;
I have this query, and it's pretty much doing what I want it too, except, I want to know the hospital name with the most hospitalizations per year, but when I add the h.name to the select, SQL makes me add it to the outer group by, which would mean I would be getting the count per year, gender and hospital name like in the subquery, instead of the hospital with most hospitalizations per year and gender, how can I add the h.name to the outer query without adding it to the outer group by?
Never use commas in the FROM clause. Always use proper, explicit, standard, readable JOIN syntax.
You want to use window functions for this:
select *
from (select count(*) as nHospitalizations, to_char(i.since, 'YYYY') as year,
u.gender, h.name,
row_number() over (partition by min(i.since) order by count(*) desc) as seqnum
from hospital h join
hospitalization i
i.hospital = h.name join
person u
on i.person = u.numberID
group by TO_CHAR(i.since, 'YYYY'), u.gender, h.name
) x
where serqnum = 1

How can I show the maximum score of each department with their names

I can select maximum the score of each department but I can't show the name of each person associated with the max score.
I tried to select the name and the maximum grade (with maximum function) but it doesn't work:
select max(stgrade)as highscore,StName,DepName --department
from TBL_DEPARTMANTS d
inner join TBL_LESSONS l on d.DepID=l.LessonID
inner join TBL_GRADES g on g.lessonid=l.LessonID
inner join TBL_STUDENT s on s.STID=g.stid
group by DepName,StName
order by DepName,highscore desc
You may try this...
select * from ( select rank() over (partition by DepName order by stgrade desc) as Slno, stgrade, stname, DepName
from TBL_DEPARTMANTS d
inner join TBL_LESSONS l on d.DepID=l.LessonID
inner join TBL_GRADES g on g.lessonid=l.LessonID
inner join TBL_STUDENT s on s.STID=g.stid ) as dep where dep.slno=1
First create rank() in decreasing order of grade for individual department. then select top record for same.
Note: Use RANK() or DENSE_RANK(), both will work fine for top 1 record, while if you want to select n highest grade then use DENSE_RANK(), at the last for slno pass n'th record you want to select.
Always hard to do theory selects, but while DarkRob's solution is good, it will remove students if for instance two people are best. This is why I love using cross apply:
select
d.Depname
, s.StName
, g.stgrade
from TBL_DEPARTMANTS d
inner join TBL_LESSONS l on
d.DepID=l.LessonID
inner join TBL_GRADES g on
g.lessonid=l.LessonID
inner join TBL_STUDENT s on
s.STID=g.stid
cross apply (
select
sub_d.DepID
, max(sub_g.stgrade) as maxgrade
from TBL_DEPARTMANTS sub_d
inner join TBL_LESSONS sub_l on
sub_d.DepID=sub_l.LessonID
inner join TBL_GRADES sub_g on
sub_g.lessonid=sub_l.LessonID
where sub_d.Dep_ID = d.Dep_ID
group by sub_d.DepID
) as sub
where g.stgrade = sub.maxgrade
This way you will get all the people with max grade per department and not just one.

i cant do the min of a sum of values order by

im working in sql server 2005
i dont know how to get the min value of the column which this returns. i have tried different ways but dont get the solution. Thanks
select sum(c.duration)
from song c , disc d, have e
where d.cod = e.cod AND e.can = c.cod
group by d.name
tables:
song have disc
-------- ------- -----------
cod(int) can(int) cod
title cod name
duration date
If you just want the minimum from the summations, then a simple ordering will do.
select top 1 sum(c.duration) as SumDuration
from song c
inner join have e on e.can = c.cod
inner join disc d on d.cod = e.cod
group by d.name
order by SumDuration asc
If you want to output all the summed records that have that minimum, then using a CTE should work
; with
CTE as (
select d.name, sum(c.duration) as SumDuration
from song c
inner join have e on e.can = c.cod
inner join disc d on d.cod = e.cod
group by d.name
)
select name, SumDuration
from CTE
where SumDuration = (
select min(SumDuration)
from CTE
)

Very hard greatest n per group query

I have a very complexe query here, I try to give you an overview about the necessary tables here:
RPG
RPGCharacter
RPGPost
User
We have X Chars per RPG, x Posts per Char. 1 User can have X Chars, but 1 Char only depens on 1 User.
What I want is a query in which I got the last post per RPG within information about the Username who wrote this, the character and the RPG itself addition to a number how much RPGPosts per RPG we have (total).
This is how far I solved it until now:
SELECT c.RPGID, c.Name, DateTime, r.Name, u.Username, t.count
FROM dbo.RPGCharacter c inner join
(
SELECT CharacterID,
MAX(DateTime) MaxDate
FROM RPGPost
GROUP BY CharacterID
) MaxDates ON c.RPGCharacterID = MaxDates.CharacterID
INNER JOIN RPGPost p ON MaxDates.CharacterID = p.CharacterID
AND MaxDates.MaxDate = p.DateTime
Inner join RPG r on c.RPGID = r.RPGID
Inner join [User] u on u.UserID = c.OwnerID
inner join (Select RPG.RPGID, Count(*) as Count from RPGPost
inner join RPGCharacter on RPGPost.CharacterID = RPGCharacter.RPGCharacterID
inner join RPG on RPG.RPGID = RPGCharacter.RPGID
where RPGPost.IsDeleted = 0
Group by RPG.RPGID) t on r.RPGID = t.RPGID
Order by DateTime desc
Result : http://abload.de/image.php?img=16iudw.jpg
This query gives me all I want but has an Errors:
1) It gives me the last post per Character, but I need the last Post per RPG
Does this help? This should give you the last post per CharacterID in the RPGPost table and include the total number of posts for that CharacterID.
WITH RankedPost AS (
SELECT
P.PostID,
P.CharacterID,
P.DateTime
RANK() OVER (
PARTITION BY CharacterID,
ORDER BY DateTime DESC) Rank,
RANK() OVER (
PARTITION BY CharacterID,
ORDER BY DateTime ASC) Count
FROM RPGPost P)
SELECT
P.DateTime
P.CharacterID,
P.Count
FROM RankedPost P
WHERE
RankedPost.Rank = 0;

SQL Joins Clarification

I wish to display the hospitalid,hosp name and hosp type for the hospital which have/has the highest no of doctors associated with them.
I have two tables:
Doctor: doctorid, hospitalid
Hospital: hospitalid, hname, htype
SELECT d.hospitalid,h.hname,h.htype
FROM doctor d
INNER JOIN hospital h ON d.hospitalid = h.hospitalid
GROUP BY d.hospitalid,h.hname,h.htype
HAVING MAX(count(d.doctorid));
I tried the above code, but i get an error "group func is nested too deeply". How should i modify d code?
This is a common error when learning SQL, thinking that having Max(col) says "keep only the row with the max". It simply means having <some function on the column> without any condition. For instance, you could say having count(d.doctorid) = 1 to get hospitals with only one doctor.
The way to do this is to order the columns and then take the first row. However, the syntax for "take the first row" varies by database. The following works in many SQL dialects:
SELECT d.hospitalid,h.hname,h.htype
FROM doctor d INNER JOIN
hospital h
ON d.hospitalid = h.hospitalid
GROUP BY d.hospitalid,h.hname,h.htype
order by count(d.doctorid) desc
limit 1;
In SQL Server and Sybase, the syntax is:
SELECT top 1 d.hospitalid,h.hname,h.htype
FROM doctor d INNER JOIN
hospital h
ON d.hospitalid = h.hospitalid
GROUP BY d.hospitalid,h.hname,h.htype
order by count(d.doctorid) desc;
In Oracle:
select t.*
from (SELECT d.hospitalid,h.hname,h.htype
FROM doctor d INNER JOIN
hospital h
ON d.hospitalid = h.hospitalid
GROUP BY d.hospitalid,h.hname,h.htype
order by count(d.doctorid) desc
) t
where rownum = 1;
EDIT (based on comment):
To get all rows with the maximum, then you can do something similar to your original query. It is just more complicated. You can calculate the maximum number using a subquery and do the comparison in the having clause:
SELECT d.hospitalid, h.hname, h.htype
FROM doctor d INNER JOIN
hospital h
ON d.hospitalid = h.hospitalid join
GROUP BY d.hospitalid,h.hname,h.htype
having count(d.doctorid) = (select max(NumDoctors)
from (select hospitalid, count(*) as NumDoctors
from hospitalId
group by hospitalid
) hd
)
As a note, there are easier mechanisms in other databases.
This is how I would write it for SQL Server. THe specific details might vary depending teh database backend you are using.
SELECT TOP 1 a.hospitalid,a.hname,a.htype
FROM
(SELECT d.hospitalid,h.hname,h.htype, count(d.doctorid) as doctorcount FROM doctor d INNER JOIN hospital h ON d.hospitalid = h.hospitalid
GROUP BY d.hospitalid,h.hname,h.htype) a
ORDER BY doctorcount DESC;