tornup
tornup

Reputation: 263

Compare Multiple rows In SQL Server

I have a SQL Server database full of the following (fictional) data in the following structure:

ID | PatientID | Exam | (NON DB COLUMN FOR REFERENCE)
------------------------------------
1  | 12345     | CT   | OK
2  | 11234     | CT   | OK(Same PID but Different Exam)
3  | 11234     | MRI  | OK(Same PID but Different Exam)
4  | 11123     | CT   | BAD(Same PID, Same Exam)
5  | 11123     | CT   | BAD(Same PID, Same Exam)
6  | 11112     | CT   | BAD(Conflicts With ID 8)
7  | 11112     | MRI  | OK(SAME PID but different Exam)
8  | 11112     | CT   | BAD(Conflicts With ID 6)
9  | 11123     | CT   | BAD(Same PID, Same Exam)
10 | 11123     | CT   | BAD(Same PID, Same Exam)

I am trying to write a query with will go through an identify everything that isn't bad as per my example above.

Overall, a patient (identified by PatientId) can have many rows, but may not have 2 or more rows with the same exam!

I have attempted various modifications of exams I found on here but still with no luck.

Thanks.

Upvotes: 0

Views: 75

Answers (5)

jarlh
jarlh

Reputation: 44766

Select those patients that never have 2 or more exams of same type.

select * from patients t1
where not exists (select 1 from patients t2
                  where t1.PatientID = t2.PatientID
                  group by exam
                  having count(*) > 1)

Or, if you want all rows, like in your example:

select ID,
       PatientID,
       Exam,
       case when exists (select 1 from patients t2
                         where t1.PatientID = t2.PatientID
                         group by exam
                         having count(*) > 1) then 'BAD' else 'OK' end
from patients

Upvotes: 0

Christian Phillips
Christian Phillips

Reputation: 18759

If you don't want to use a CTE or Count Over, you can also group the Source table, and select from there...(but I'd be surprised if @Gordon was too far off the mark with the original answer :) )

SELECT  a.PatientID, a.Exam, CASE WHEN a.cnt > 1 THEN 'BAD' ELSE 'OK' END
FROM    ( SELECT    PatientID
                   ,Exam
                   ,COUNT(*) AS cnt
          FROM      tableName
          GROUP BY  Exam
                   ,PatientID
        ) a

Upvotes: 0

Vishal Gajjar
Vishal Gajjar

Reputation: 1029

You can also use:

 ;WITH  CTE_Patients
      (ID, PatientID, Exam, RowNumber)
AS
(
      SELECT      ID, PatientID, Exam
                  ROW_NUMBER() OVER (PARTITION BY PatientID, Exam ORDER BY ID)
      FROM        YourTableName
)
SELECT      TableB.ID, TableB.PatientID, TableB.Exam, [DuplicateOf] = TableA.ID
FROM        CTE_Patients TableB
INNER JOIN CTE_Patients TableA
            ON    TableB.PatientID = TableA.PatientID
            AND   TableB.Exam = TableA.Exam
WHERE       TableB.RowNumber > 1 -- Duplicate rows
AND         TableA.RowNumber = 1 -- Unique rows

I have a sample here: SQL Server – Identifying unique and duplicate rows in a table, you can identify unique rows as well as duplicate rows

Upvotes: 0

Deep
Deep

Reputation: 3202

use Count() over() :

select *,case when COUNT(*) over(partition by PatientID, Exam) > 1 then 'bad' else 'ok' 
from yourtable 

Upvotes: 0

Gordon Linoff
Gordon Linoff

Reputation: 1269773

You seem to want to identify duplicates, ranking them as good or bad. Here is a method using window functions:

select t.id, t.patientid, t.exam,
       (case when cnt > 1 then 'BAD' else 'OK' end)
from (select t.*, count(*) over (partition by patientid, exam) as cnt
      from table t
     ) t;

Upvotes: 3

Related Questions