SQL query to only pull most recent value

The query below will pull what I need but pulls all obsvalues and I only want it to pull the most recent. The completeddate is probably what needs to be used in some sort of nested select but I'm not sure how to do this and return values for all rather than just values for one person.

SELECT distinct obsvalue, p.person_id, p.last_name, p.first_name, p.person_nbr, o2.completeddate
FROM order_ o2
INNER JOIN ncsuds_lab_test_desc d ON RTRIM(o2.actText) = RTRIM(d.test_desc) and d.order_ind = 'Y' AND d.selected_diag_id = 42
inner join person p on o2.person_id = p.person_id
WHERE o2.obsvalue IS NOT NULL
AND ISNUMERIC(o2.obsvalue) = 1
and o2.completeddate > '20150101'
order by completeddate desc
biotecAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Jim HornSQL Server Data DudeCommented:
<knee-jerk reaction>

Which column defines 'most recent'?  If you mean the most recent o2.completedate, then you'll need a MAX.

SELECT obsvalue, p.person_id, p.last_name, p.first_name, p.person_nbr, 
   MAX(o2.completeddate) as most_recent_completeddate
FROM order_ o2
   INNER JOIN ncsuds_lab_test_desc d ON RTRIM(o2.actText) = RTRIM(d.test_desc) and d.order_ind = 'Y' AND d.selected_diag_id = 42
   INNER JOIN person p on o2.person_id = p.person_id
WHERE o2.obsvalue IS NOT NULL
   AND ISNUMERIC(o2.obsvalue) = 1
   AND o2.completeddate > '20150101'
GROUP BY obsvalue, p.person_id, p.last_name, p.first_name, p.person_nbr
ORDER BY completeddate desc

Open in new window

btw note the use of indentation and capitalizing all SELECT .. FROM ... keywords.  Makes it easier to read.   Also I removed the DISTINCT as the GROUP BY handles that.

Check out SQL Server GROUP BY Solutions for some extra info on grouping.
pcelbaCommented:
I would try ROW_NUMBER() here:
SELECT * FROM (
  SELECT ROW_NUMBER() OVER (p.person_id, p.person_nbr ORDER BY completeddate desc) rowno, 
         obsvalue, p.person_id, p.last_name, p.first_name, p.person_nbr, o2.completeddate
    FROM order_ o2
   INNER JOIN ncsuds_lab_test_desc d ON RTRIM(o2.actText) = RTRIM(d.test_desc) and d.order_ind = 'Y' AND d.selected_diag_id = 42
   inner join person p on o2.person_id = p.person_id
   WHERE o2.obsvalue IS NOT NULL
     AND ISNUMERIC(o2.obsvalue) = 1
     and o2.completeddate > '20150101') insl
  WHERE rowno = 1 

Open in new window

biotecAuthor Commented:
This is getting closer but still returns duplicates for many of the persons we're returning the values for. In other words the first two rows in the returned data set are the same person with a value for Sep and another for Nov. It is returning both and I'd only want it to return the entry for Nov.
Your Guide to Achieving IT Business Success

The IT Service Excellence Tool Kit has best practices to keep your clients happy and business booming. Inside, you’ll find everything you need to increase client satisfaction and retention, become more competitive, and increase your overall success.

pcelbaCommented:
A small fix:
SELECT * FROM (
  SELECT ROW_NUMBER() OVER (PARTITION BY p.person_id, p.person_nbr ORDER BY o2.completeddate desc) rowno, 
         obsvalue, p.person_id, p.last_name, p.first_name, p.person_nbr, o2.completeddate
    FROM order_ o2
   INNER JOIN ncsuds_lab_test_desc d ON RTRIM(o2.actText) = RTRIM(d.test_desc) and d.order_ind = 'Y' AND d.selected_diag_id = 42
   inner join person p on o2.person_id = p.person_id
   WHERE o2.obsvalue IS NOT NULL
     AND ISNUMERIC(o2.obsvalue) = 1
     and o2.completeddate > '20150101') insl
  WHERE rowno = 1 

Open in new window

This should not return duplicate persons

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
biotecAuthor Commented:
There is a syntax error near the first Order By. Not sure that can be wrapped inside parens like that.
pcelbaCommented:
The ROW_NUMBER() requires SQL Server 2005 or newer. The OVER (PARTITION BY ... ORDER BY ...) clause should be OK because it belongs to the ROW_NUMBER().
More info: https://msdn.microsoft.com/en-us/library/ms186734.aspx

If you are using different SQL engine then tell the version please.

BTW, multiplicities on output can also be caused by the INNER JOIN ncsuds_lab_test_desc  definition. To join two tables via text description column is not a standard. What is the reason to join ncsuds_lab_test_desc table?
biotecAuthor Commented:
I don't quite understand what the Row_Number Over Partition does but it seemed to work. Thanks
Jim HornSQL Server Data DudeCommented:
>This is getting closer but still returns duplicates for many of the persons we're returning the values for.
Please show us some sample data, both your data source and what the above queries are returning.
pcelbaCommented:
ROW_NUMBER() generates line numbers for your data and the OVER() defines rules for such numbering, namely grouping (partitioning) and the order of the data.

To get the latest result for each person we used p.person_id for grouping (p.person_nbr is not necessary probably) and ordered the data by  completeddate DESC.

Thanks to the descending order the latest result has ROW_NUMBER() = 1 for each person.

I agree the ROW_NUMBER() is a little bit unclear at the first view.

BTW, this part of your query is still unclear to me:
   INNER JOIN ncsuds_lab_test_desc d ON RTRIM(o2.actText) = RTRIM(d.test_desc) and d.order_ind = 'Y' AND d.selected_diag_id = 42

but that's not important maybe.
biotecAuthor Commented:
Thank you this is helpful. I'm still unclear on the inner join too, but it doesn't seem to filter anything out that I need so I have to trust the vendor on this one.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft SQL Server

From novice to tech pro — start learning today.