views:

56

answers:

4

I'm trying to write a query that brings back patients who have had an office visit at least a year before the most recent one. The various ways I'm thinking of get all twisted up in my head, so I was wondering if anyone out there can see an obvious way to write it that I'm missing. Don't worry too much about the exact syntax and naming -- I should be able to translate it. :-)

Thanks!

+1  A: 
select distinct * from PatientHistory
where lastVisit = date_sub(lastVisit,interval 1 year)
Gio
There's no DATE_SUB in Oracle -- that's MySQL syntax.
OMG Ponies
Perhaps: `ADD_MONTHS(TO_DATE('01-JAN-2000'), -12))`
jnpcl
@jnpcl: TO_DATE needs the date format for that to work.
OMG Ponies
+3  A: 

Use:

SELECT ph.*
  FROM PATIENT_HISTORY ph
 WHERE ph.visit_date >= (SYSDATE - 365)

...or:

SELECT ph.*
  FROM PATIENT_HISTORY ph
 WHERE ph.visit_date >= ADD_MONTHS(SYSDATE, -12)

ADD_MONTHS is self-explanatory. In Oracle, SYSDATE returns the current date and time, and you can manipulate Oracle DATE (includes time) by adding/subtracting a number (which is interpreted as the number of days).

For patients with a record that is a year or more in the past:

SELECT a.*
  FROM PATIENT_HISTORY a
 WHERE EXISTS(SELECT NULL
                FROM PATIENT_HISTORY b
               WHERE b.visit_date <= ADD_MONTHS(a.visit_date, -12))
OMG Ponies
Based on the OP's comments, I think he is interested in patients that have been treated for at least a year, not necessarily within a year of today's date. Your query would omit someone who started service on 4/1/2008 and whose last appointment was on 6/30/2009.
Scott Mitchell
@Scott Mitchell: I see your point, but is it valid to have someone who was treated for a year, years in the past? It's something the OP has to clarify better.
OMG Ponies
@OMG Ponies: I agree the wording is confusing and needs to be clarified. However, note the OP's comment: "I'm trying to establish that they've been treated for at least a year." That leads me to believe that he wants to see patients that were treated for at least a year, even if their last treatment was more than a year ago.
Scott Mitchell
@Scott Mitchell: Updated
OMG Ponies
@OMG Ponies: I still don't think you've got it. Your second query brings back all patients with an appointment that is a year or more in the past. What he wants (I think) is that there has been at least a year between the patient's FIRST visit and their most recent visit, whenever those happen to be.
Scott Mitchell
@Scott Mitchell: I don't see such a requirement regarding first ever appointment in the last comment by the OP.
OMG Ponies
Interesting, but I think my actual situation is a bit too complicated for this to work. Maybe. If the windowing function solution doesn't work, I'll come back to this one. Thanks!
SarekOfVulcan
@SarekOfVulcan: It would be easier to help if you didn't abstract so much.
OMG Ponies
True, but trust me, you don't want to see what this query is going to look like when I get all of the requirements pasted together. :-)
SarekOfVulcan
@SarekOfVulcan: Hasn't stopped others
OMG Ponies
+1  A: 

If you want to determine whether a patient has been treated for at least a year (which your comment makes it sound like) then couldn't you do a query like:

SELECT *
FROM Patients p
WHERE 
    DATEDIFF(d, 
             (SELECT MIN(AppointmentDate) FROM Appointments a WHERE a.PatientID = p.PatientID),
             (SELECT MAX(AppointmentDate) FROM Appointments a WHERE a.PatientID = p.PatientID)) >= 365

I don't know if that syntax will work offhand, but the concept is to say, "Return only those patients where the number of days since their earliest and most recent appointments is at least 365 days.

Scott Mitchell
OMG Ponies
Ah, now that has possibilities. Thanks!
SarekOfVulcan
@OMG Ponies: Yes, but SharekOfVulcan said in his question, "Don't worry too much about the exact syntax and naming."
Scott Mitchell
By that logic, you'd have the logic for how solve the issue but still need to get Oracle syntax for it (unless this is for another database) -- which would the same point as where the OP started. But the logic is identical to the EXISTS example I gave - don't need to check the MAX, because EXISTS returns true on the first success of the criteria.
OMG Ponies
+1  A: 

It's fairly straight to do it with WINDOW FUNCTIONS in Oracle.

If your VISITS table is something like:

create table visits (
    patient_id number,
    visit_date date,
    ....
);

You can use this simple query:

select patient_id, visit_date, 
       lead(visit_date, 1, null) 
           over (partition by patient_id order by visit_date) as next_visit_date
  from visits;

And will get in one row, visit_date value, and following visit_date value for the same patient.

Then with a simple where, you can check for your one year condition.

Pablo Santa Cruz
lead won't help, since they could have had lots of visits in between. Mixing this with Scott's Min/Max suggestion might be useful, though. Thanks!
SarekOfVulcan
Yes, you need to put some conditions to meet your exact requirements. I just think Window Functions are very useful for these kind of queries...
Pablo Santa Cruz