Use SQL to exclude rows with no change in specific column from query - sql

How can I exclude the yellow highlighted rows? The requirement of the query is to return only rows where the job title changed, but the raw data includes extraneous rows with different effective dates which we want to be able to automatically exclude with SQL.
This is because the source system has a record effective date column that is common to several columns. We cannot change this architecture and so need the ability to exclude records from the output.
Edit to include error image from suggested answer:

select
a.*
FROM
jobtitles a
LEFT JOIN jobtitles b
ON a.id = b.id AND
a.effdate < b.effdate
WHERE b.id IS NULL
something like that, that would get the latest job title anyway
you might be able to use that "pseudo table" to further query
on considering your question further, how about
select
MIN(effdate) as effdate, jobtitle
FROM jobtitles
group by employeeid, jobtitle
(I'm making the assumption they don't change job titles back and forth, if so you're basically screwed, so be aware of that)

If JobTitle of an employee does not reverted to previous job titles, use the following query:
SELECT EmployeeID,
Name,
JobTitle,
MAX(Name) AS Name,
MIN(EffectiveDate) AS EffectiveDate
FROM jobtitles
GROUP BY EmployeeID, JobTitle
ORDER BY EmployeeID ASC, EffectiveDate DESC
If JobTitle of employees can be reverted/change to title that they have already obtained in the past, use the following query:
Edit: Update query according to table schema provided in question
SELECT ASSOCIATE_ID,
JOB_TITLE_DESCRIPTION,
POSITION_EFFECTIVE_DATE
FROM (
SELECT
ASSOCIATE_ID,
JOB_TITLE_DESCRIPTION,
JOB_TITLE_CODE,
POSITION_EFFECTIVE_DATE,
LEAD(JOB_TITLE_CODE,1, '0') OVER (ORDER BY ASSOCIATE_ID ASC, POSITION_EFFECTIVE_DATE DESC) AS PREV_TITLE_ID
FROM EMP_JOB_HISTORY
) AS tmp
WHERE tmp.PREV_TITLE_ID <> tmp.JOB_TITLE_CODE

Related

select rows in sql with latest date from 3 tables in each group

I'm creating PREDICATE system for my application.
Please see image that I already
I have a question how can I select rows in SQL with latest date "Taken On" column tables for each "QuizESId" columns, before that I am understand how to select it but it only using one table, I learn from this
select rows in sql with latest date for each ID repeated multiple times
Here is what I have already tried
SELECT tt.*
FROM myTable tt
INNER JOIN
(SELECT ID, MAX(Date) AS MaxDateTime
FROM myTable
GROUP BY ID) groupedtt ON tt.ID = groupedtt.ID
AND tt.Date = groupedtt.MaxDateTime
What I am confused about here is how can I select from 3 tables, I hope you can guide me, of course I need a solution with good query and efficient performance.
Thanks
This is for SQL Server (you didn't specify exactly what RDBMS you're using):
if you want to get the "latest row for each QuizId" - this sounds like you need a CTE (Common Table Expression) with a ROW_NUMBER() value - something like this (updated: you obviously want to "partition" not just by QuizId, but also by UserName):
WITH BaseData AS
(
SELECT
mAttempt.Id AS Id,
mAttempt.QuizModelId AS QuizId,
mAttempt.StartedAt AS StartsOn,
mUser.UserName,
mDetail.Score AS Score,
RowNum = ROW_NUMBER() OVER (PARTITION BY mAttempt.QuizModelId, mUser.UserName
ORDER BY mAttempt.TakenOn DESC)
FROM
UserQuizAttemptModels mAttempt
INNER JOIN
AspNetUsers mUser ON mAttempt.UserId = muser.Id
INNER JOIN
QuizAttemptDetailModels mDetail ON mDetail.UserQuizAttemptModelId = mAttempt.Id
)
SELECT *
FROM BaseData
WHERE QuizId = 10053
AND RowNum = 1
The BaseData CTE basically selects the data (as you did) - but it also adds a ROW_NUMBER() column. This will "partition" your data into groups of data - based on the QuizModelId - and it will number all the rows inside each data group, starting at 1, and ordered by the second condition - the ORDER BY clause. You said you want to order by "Taken On" date - but there's no such date visible in your query - so I just guessed it might be on the UserQuizAttemptModels table - change and adapt as needed.
Now you can select from that CTE with your original WHERE condition - and you specify, that you want only the first row for each data group (for each "QuizId") - the one with the most recent "Taken On" date value.

SQL to Select lowest value, group by, other field

I'm having a problem writing a query that gives me the other fields after finding the min value of another column. I've tried this:
Select WorkOrder, min(Job), Details
From Jobs
Group by WorkOrder
But it doesn't work.
This gives me a list of the lowest Job number by WorkOrder:
Select WorkOrder, min(Job)
From Jobs
Group by WorkOrder
I want Details of the line item with the lowest Job number. What am I doing wrong?
You may try this query
Select WorkOrder, min(Job), Details
From Jobs
Group by WorkOrder, Details
When you use a GROUP BY clause, everything in your select statement has to either be an aggregate function (like min, max, ect) or has to be included in your GROUP BY clause. Details is not included in your GROUP BY clause, and so the statement won't compile. If you include Details in your GROUP BY clause you will get the min(job) of each combination of WorkOrder and Details, which is probably not what you want.
There are a few ways you can go about solving this problem. IMO the easiest would be to select your min(job) and Workorder, and then to join that result back into the jobs table and select details. To do this your jobs table must have a unique primary key.
SELECT
minWorkOrder.WorkOrder
minWorkOrder.MinJob
Jobs.Details
FROM
(Select Key, WorkOrder, min(Job) as MinJob
From Jobs
Group by Key, WorkOrder) AS minWorkOrder
INNER JOIN Jobs
ON Jobs.Key = minWorkOrder.Key
If your table does not have a unique key, then things get a littler trickier. In the scope of this query, it is probably a safe assumption that every combination of min(Job) and WorkOrder is unique. You can join on both of these fields and yous should get the right answer.
SELECT
minWorkOrder.WorkOrder
minWorkOrder.MinJob
Jobs.Details
FROM
(Select WorkOrder, min(Job) as MinJob
From Jobs
Group by WorkOrder) AS minWorkOrder
INNER JOIN Jobs
ON Jobs.Job = minWorkOrder.MinJob AND Jobs.WorkOrder = minWorkOrder.WorkOrder
you should add min() in your condition like this
Select * From Jobs Where Job in
(Select min_job From (Select WorkOrder ,min(Job) as min_job From Jobs
Group by WorkOrder)
)
You should try this:
SELECT WorkOrder, Details
from Jobs
where Job IN (SELECt min(Job), WorkOrder from Jobs GROUP BY WorkOrder);
I worked with an engineer in my department who provided this working answer:
Select A.WorkOrder, A.Job, A.Details
From(Select WorkOrder, Job, Details, Row_Number()
over( Partition by WorkOrder Order by Job ASC) as Num
From Jobs)A
where A.Num = 1
with cte as
(
select workorder,Job, Details, rank() over (partition by workorder order by job asc) as rnk
from
Jobs
)
select workorder,Job, Details from cte
where rnk = 1
Here we are ranking values in column Job in ascending order, for each workorder. Last WHERE clause rnk = 1 fetches only the Jobs with minimum value for each workorder. In case a workorder has more than 1 jobs with same value, RANK() will assign same rank to them . Hence, if a workorder has more than 1 jobs with minimum value ,this will return all of them.

MS Access SQL error

This code is supposed to select the TOP 1, but it's not working properly. Instead of showing only the TOP 1 record, it is showing tons of records. It may be because I have 2 tables referenced. In another code I only had 1 and it worked. I need to reference table attendance though so I'm not sure how to work around that. Thanks!
SELECT TOP 1 userID
FROM attendance, CFRRR
WHERE [attendance.Programs] LIKE CFRRR.program
AND [attendance.Language] LIKE CFRRR.language
AND [attendance.Status] = 'Available'
ORDER BY TS ASC
Here are the table fields for attendance: userID, username, Supervisor, Category, AttendanceDay, AttendanceTime, Programs, Language, Status, TS.
Here are the table fields for CFRRR: CFRRRID, WorkerID, Workeremail, Workername, Dateassigned, assignedby, RRRmonth, Scheduledate, scheduledtime, type, ScheduledType, caseid, language, lastname, firstname, Checkedin, Qid, status, CompletedType, comments, actiondate, verifduedate, program.
Clearly the last table has a lot of records.
SELECT TOP in MS Access differs from SELECT TOP in SQL Server and similar functionality in other databases. It returns the top rows based on the order by. Then it continues to return rows that match the last value. This is convenient sometimes, which is why SQL Server has this functionality as SELECT TOP WITH TIES.
To fix this, you need to include one or more columns that is unique for each generated row:
SELECT TOP 1 userID
FROM attendance as a,
CFRRR
WHERE a.Programs LIKE CFRRR.program AND
a.Language LIKE CFRRR.language AND
a.Status = 'Available'
ORDER BY TS ASC, userId, CFFRID

SQL - Group By unique column combination

I am trying to write a script that will return the latest values for a unique documentid-physician-patient triplet. I need the script to act similar to a group by statement, except group by only works with one column at a time. I need to date and status information for only the most recent unique triplet. Please let me know what you will need to see from me to help. Here is the current, very bare, statement:
SELECT
TransmissionSend.CreateTimestamp,
TransmissionSendItem.Status,
TransmissionSendItem.PhysicianId,
TransmissionSendItem.DocumentIdDisplay,
Utility.SqlFunctions_NdnListToAccountList(TransmissionSendItem.NdocNum) AS AccountNum
FROM
Interface_SFAX.TransmissionSend,
Interface_SFAX.TransmissionSendItem
WHERE
TransmissionSend.ID = TransmissionSendItem.childsub --I don't know exactly what this does, I did not write this script. It must stay here though for the exact results.
ORDER BY TransmissionSend.CreateTimestamp DESC -- In the end, each latest result of the unique triplet will be ordered from most recent to oldest in return
My question is, again, how can I limit results to only the latest status for each physician id, document id, and account number combination?
First select the MAX(date) with the documentid GROUP BY documentid then select all data from the table by the first select result for example with an inner join.
SELECT table.additionalData, J.id, J.date
FROM table
INNER JOIN (SELECT id, MAX(date) AS date
FROM table GROUP BY id) AS J
ON J.id = table.id
AND J.date /* this is the max date */ = table.date

How to find max value and its associated field values in SQL?

Say I have a list of student names and their marks. I want to find out the highest mark and the student, how can I write one select statement to do that?
Assuming you mean marks rather than remarks, use:
select name, mark
from students
where mark = (
select max(mark)
from students
)
This will generally result in a fairly efficient query. The subquery should be executed once only (unless your DBMS is brain-dead) and the result fed into the second query. You may want to ensure that you have an index on the mark column.
If you don't want to use a subquery:
SELECT name, remark
FROM students
ORDER BY remark DESC
LIMIT 1
select name, remarks
from student
where remarks =(select max(remarks) from student)
If you are using a database that supports windowing,
SELECT name, mark FROM
(SELECT name, mark, rank() AS rk
FROM student_marks OVER (ORDER BY mark DESC)
) AS subqry
WHERE subqry.rk=1;
This probably does not run as fast as the mark=(SELECT MAX(mark)... style query, but it would be worth checking out.
In SQL Server:
SELECT TOP 1 WITH TIES *
FROM Students
ORDER BY Mark DESC
This will return all the students that have the highest mark, whether there is just one of them or more than one. If you want only one row, drop the WITH TIES specifier. (But the actual row is not guaranteed to be always the same then.)
You can create view and join it with original table:
V1
select id , Max(columName)
from t1
group by id
select * from t1
where t1.id = V1.id and t1.columName = V1.columName
this is right if you need Max Values with related info
I recently had a need for something "kind of similar" to this post and wanted to share a technique. Say you have an Order and OrderDetail table, and you want to return info from the Order table along with the product name associated with the highest priced detail row. Here's a way to pull that off without subtables, RANK, etc.. The key is to create and aggregate that combined the key and value from the detailed table and then just max on that and substring out the value you want.
create table CustOrder(ID int)
create table CustOrderDetail(OrderID int, Price money, ProdName varchar(20))
insert into CustOrder(ID) values(1)
insert into CustOrderDetail(OrderID,Price,ProdName) values(1,10,'AAA')
insert into CustOrderDetail(OrderID,Price,ProdName) values(1,50,'BBB')
insert into CustOrderDetail(OrderID,Price,ProdName) values(1,10,'CCC')
select
o.ID,
JoinAggregate=max(convert(varchar,od.price)+'*'+od.prodName),
maxProd=
SUBSTRING(
max(convert(varchar,od.price)+'*'+od.prodName)
,CHARINDEX('*',max(convert(varchar,od.price)+'*'+convert(varchar,od.prodName))
)+1,9999)
from
CustOrder o
inner join CustOrderDetail od on od.orderID = o.ID
group by
o.ID