Select duplicate by youngest date - sql

I have run into a snag.
A got a DB with employees with multiple startdates.
Employees can start and can get a new contract later.
FE.
ID NAME DATEEMPLOYED FUNCTION
1 Paul 01/01/2016 Director
2 Paul 01/01/2015 Staff Member
3 Jeff 02/05/2016 Director
4 Jeff 01/05/2015 Employee
5 Jeff 01/05/2014 Employee
6 Eric 05/06/2015 Employee
Now I need to get the ID from the latest and the youngest date.
I want to copy the function of the row with the latest date to the oldest date and then delete all but the oldest.
The oldest I can find by:
SELECT * FROM [database].[dbo].[Personel] t WHERE DATEEMPLOYED NOT IN (SELECT MAX(DATEEMPLOYED) AS LastUpdate FROM [database].[dbo].[Personel] GROUP BY Naam,Voornaam)
This returns 10 rows...
Now to find the youngest...
I thought, it would be as easy as changing MAX(DATEEMPLOYED) to MIN(DATEEMPLOYED)...
But I guess not because this only returns 6 rows...
I'm running a live DB so no sample date...
The expected output of the query for the max date per employee is ID 1 and 3 ... The expected output for min date is ID 2 and 5 ...
No number 6
I'am running MS SQL trough an ASP.net application...
The query posted I'm running on the SQL server itself for testing...
Later I'll adapt for the ASP.Net
I want to automatize the deletion of duplicate employees.
Where did i go wrong?

DEPENDING on your version, you could use the window function
Declare #YourTable table (ID int,NAME varchar(50), DATEEMPLOYED Date, [FUNCTION] varchar(50))
Insert Into #YourTable values
(1,'Paul','01/01/2016','Director'),
(2,'Paul','01/01/2015','Staff Member'),
(3,'Jeff','02/05/2016','Director'),
(4,'Jeff','01/05/2015','Employee'),
(5,'Jeff','01/05/2014','Employee'),
(6,'Eric','05/06/2015','Employee')
;with cteBase as (
Select Distinct Name
,Times = count(*) over (Partition By Name)
,MinID = min(ID) over (Partition By Name)
,MaxID = max(ID) over (Partition By Name)
,MinDate = min(DATEEMPLOYED) over (Partition By Name Order By DATEEMPLOYED)
,MaxDate = max(DATEEMPLOYED) over (Partition By Name Order By DATEEMPLOYED Desc)
From #YourTable
)
Select * from cteBase where Times>1
Returns
Name Times MinID MaxID MinDate MaxDate
Jeff 3 3 5 2014-01-05 2016-02-05
Paul 2 1 2 2015-01-01 2016-01-01

Does your DB have NULL dates, if so you need to check for those.

Related

Access Query: Subtract last 2 values, specific to ID

Help appreciated! My table is setup as follows:
fake data TableName = GAD7
[PatientID Date Value
Sam 10/21/2022 15
George 06/12/2022 7
Luke 09/03/2021 11
Sam 05/15/2020 20
George 12/02/2017 2
George 01/01/1992 6][1]
So I have potentially multiple rows of the same patient, w/different dates.
I need to create a query that subtracts the LAST 2/most recent values for each patient.
So my query would show only those with 2+ records. Negative values are fine/expected.
My successful query would then show:
PatientID (LastScore - 2nd_toLastScore)
Sam -5.0
George 5.0
Luke is not shown because he only has one value
I was able to formulate a query to show only those PatientIDs with >= 2 records and last date and last value. I am not sure how to get the second from last date/value AND THEN subtract those values.
Access query
The SQL view :
SELECT GAD7.PatientID, Count(GAD7.PatientID) AS CountOfPatientID, Last(GAD7.TestDate) AS LastDate, Last(GAD7.Score) AS LastScore
FROM GAD7
GROUP BY GAD7.PatientID
HAVING (((Count(GAD7.PatientID))>=2))
ORDER BY GAD7.PatientID;
Consider:
Query1: Score1
SELECT GAD7.*
FROM GAD7
WHERE 1=(SELECT Count(*)+1 FROM GAD7 AS G7
WHERE G7.PatientID=GAD7.PatientID AND G7.TestDate>GAD7.TestDate);
Query2: Score2
SELECT GAD7.*
FROM GAD7
WHERE 2=(SELECT Count(*)+1 FROM GAD7 AS G7
WHERE G7.PatientID=GAD7.PatientID AND G7.TestDate>GAD7.TestDate);
Query3:
SELECT Score2.PatientID, [Score2].[Score]-[Score1].[Score] AS D
FROM Score1 INNER JOIN Score2 ON Score1.PatientID = Score2.PatientID;
Could nest the SQL statements for an all-in-one query.
Or this all-in-one version using TOP N to pull previous Score:
SELECT GAD7.*, (SELECT TOP 1 Score FROM GAD7 AS Dupe
WHERE Dupe.PatientID = GAD7.PatientID AND Dupe.TestDate<GAD7.TestDate
ORDER BY Dupe.TestDate DESC) AS PrevScore
FROM GAD7 WHERE PatientID IN
(SELECT PatientID FROM GAD7 GROUP BY PatientID HAVING Count(*)>1)
AND 1=(SELECT Count(*)+1 FROM GAD7 AS G7 WHERE G7.PatientID=GAD7.PatientID AND G7.TestDate>GAD7.TestDate);

Get the smallest start date for several elements and group them?

I have this table called "Class". Class has Class ID, Room ID, and Class Start Time.
For example:
Class_ID: 1
Room_ID: 1234
Class_Start_Time: 07/11/2016 1 pm
Class_ID: 2
Room_ID: 1234
Class_Start_Time: 07/11/2016 9 am
Class_ID: 4
Room_ID: 1235
Class_Start_Time: 07/11/2016 8 am
I need to get the smallest start time for each room. Meaning that Room 1234 would get 07/11/2016 9 am and Room 1235 would get 07/11/2016 8 am
(only one start time). I tried this:
SELECT Room_ID
FROM Courses
GROUP BY Room_ID
ORDER BY Class_Start_Time
It asks me to include the start time in the group by, but if I do so, it would give me all the start times and repeated rooms, when what I need is only one of each room and ordered by the room's respective start time. So...
Room_ID = 1235
Start time = 07/11/2016 8 am
Room_ID = 1234
Start time = 07/11/2016 9 am
The order of the rooms doesn't matter is the order of each smallest start time that does. Any suggestions?
You can use the ranking functions in SQL Server such as the Row_Number.
You can do some reading here:
https://msdn.microsoft.com/en-us/library/ms186734.aspx
I think this is what you are looking for.
Create Table Courses
(
ClassId int null,
Room_Id int null,
Class_Start_Time datetime null
)
Insert into Courses
values ('1','1234','2016-07-11 13:00:00.000')
Insert into Courses
values ('2','1234','2016-07-11 09:00:00.000')
Insert into Courses
values ('4','1235','2016-07-11 08:00:00.000')
Select t.ClassID,t.Room_Id,t.Class_Start_Time from
(
SELECT *,row_number() over (partition by Room_Id order by Class_Start_Time) as SequenceNumber
from Courses
)t
Where t.SequenceNumber=1
order by Class_Start_Time
Use MIN(), give your Class_Start_Time an alias and order by it.
SELECT Room_Id, MIN(Class_Start_Time) Start
FROM Courses
GROUP BY Room_Id
ORDER BY Start

Complex SQL query or queries

I looked at other examples, but I don't know enough about SQL to adapt it to my needs. I have a table that looks like this:
ID Month NAME COUNT First LAST TOTAL
------------------------------------------------------
1 JAN2013 fred 4
2 MAR2013 fred 5
3 APR2014 fred 1
4 JAN2013 Tom 6
5 MAR2014 Tom 1
6 APR2014 Tom 1
This could be in separate queries, but I need 'First' to equal the first month that a particular name is used, so every row with fred would have JAN2013 in the first field for example. I need the 'Last" column to equal the month of the last record of each name, and finally I need the 'total' column to be the sum of all the counts for each name, so in each row that had fred the total would be 10 in this sample data. This is over my head. Can one of you assist?
This is crude but should do the trick. I renamed your fields a bit because you are using a bunch of "RESERVED" sql words and that is bad form.
;WITH cte as
(
Select
[NAME]
,[nmCOUNT]
,ROW_NUMBER() over (partition by NAME order by txtMONTH ASC) as 'FirstMonth'
,ROW_NUMBER() over (partition by NAME order by txtMONTH DESC) as 'LastMonth'
,SUM([nmCOUNT]) as 'TotNameCount'
From Table
Group by NAME, [nmCOUNT]
)
,cteFirst as
(
Select
NAME
,[nmCOUNT]
,[TotNameCount]
,[txtMONTH] as 'ansFirst'
From cte
Where FirstMonth = 1
)
,cteLast as
(
Select
NAME
,[txtMONTH] as 'ansLast'
From cte
Where LastMonth = 1
Select c.NAME, c.nmCount, c.ansFirst, l.ansLast, c.TotNameCount
From cteFirst c
LEFT JOIN cteLast l on c.NAME = l.NAME

SQL - Set field value based on count of previous rows values

I have the following table structure in Microsoft SQL:
ID Name Number
1 John
2 John
3 John
4 Mark
5 Mark
6 Anne
7 Anne
8 Luke
9 Rachael
10 Rachael
I am looking to set the 'Number' field to the number of times the 'Name' field has appeared previously, using SQL.
Desired output as follows:
ID Name Number
1 John 1
2 John 2
3 John 3
4 Mark 1
5 Mark 2
6 Anne 1
7 Anne 2
8 Luke 1
9 Rachael 1
10 Rachael 2
The table is ordered by 'Name', so there is no worry of 'John' appearing under ID 11 again, using my example.
Any help would be appreciated. I'm not sure if I can do this with a simple SELECT statement, or whether I will need an UPDATE statement, or something more advanced.
Use ROW_NUMBER:
SELECT ID, Name,
ROW_NUMBER() OVER (PARTITION BY Name
ORDER BY ID) AS Number
FROM mytable
There is no need to add a field for this, as the value can be easily calculated using window functions.
You should be able to use the ROW_NUMBER() function within SQL Server to partition each group (by their Name property) and output the individual row in each partition :
SELECT ID,
Name,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY ID) AS Number
FROM YourTable
ORDER BY ID
You can see what your data looks like prior to the query :
and then after it is executed :
If your system doesnt support OVER PARTITION, you can use following code:
SELECT
ID,
Name,
(
SELECT
SUM(counterTable.nameCount)
FROM
mytable innerTable
JOIN (SELECT 1 as nameCount) as counterTable
WHERE
innerTable.ID <= outerTable.ID
AND outerTable.Name = innerTable.Name
) AS cumulative_sum
FROM
mytable outerTable
ORDER BY outerTable.ID
Following CREATE TABLE statement I used and then filled in your data:
CREATE TABLE `mytable` (
`ID` INT(11) NULL DEFAULT NULL,
`Name` VARCHAR(50) NULL DEFAULT NULL
);
This should work with DBS not supporting OVER PARTITION like MySQL, Maria, ...

SQL: How to make a query that return last created row per each user from table's data

Consider following table's data
ID UserID ClassID SchoolID Created
2184 19313 10 28189 2010-10-25 14:16:39.823
46697 19313 10 27721 2011-04-04 14:50:49.433
•47423 19313 11 27721 2011-09-15 09:15:51.740
•47672 19881 11 42978 2011-09-19 17:31:12.853
3176 19881 11 42978 2010-10-27 22:29:41.130
22327 19881 9 45263 2011-02-14 19:42:41.320
46661 32810 11 41861 2011-04-04 14:26:14.800
•47333 32810 11 51721 2011-09-13 22:43:06.053
131 32810 11 51721 2010-09-22 03:16:44.520
I want to make a sql query that return the last created row for each UserID in which the result will be as below ( row that begin with • in the above rows ) :
ID UserID ClassID SchoolID Created
47423 19313 11 27721 2011-09-15 09:15:51.740
47672 19881 11 42978 2011-09-19 17:31:12.853
47333 32810 11 51721 2011-09-13 22:43:06.053
You can use a CTE (Common Table Expression) with the ROW_NUMBER function:
;WITH LastPerUser AS
(
SELECT
ID, UserID, ClassID, SchoolID, Created,
ROW_NUMBER() OVER(PARTITION BY UserID ORDER BY Created DESC) AS 'RowNum')
FROM dbo.YourTable
)
SELECT
ID, UserID, ClassID, SchoolID, Created,
FROM LastPerUser
WHERE RowNum = 1
This CTE "partitions" your data by UserID, and for each partition, the ROW_NUMBER function hands out sequential numbers, starting at 1 and ordered by Created DESC - so the latest row gets RowNum = 1 (for each UserID) which is what I select from the CTE in the SELECT statement after it.
I know this is an old question at this point, but I was having the same problem in MySQL, and I think I have figured out a standard sql way of doing this. I have only tested this with MySQL, but I don't believe I am using anything MySQL-specific.
select mainTable.* from YourTable mainTable, (
select UserID, max(Created) as Created
from YourTable
group by UserID
) dateTable
where mainTable.UserID = dateTable.UserID
and mainTable.Created = dateTable.Created