2

Ok SO, here's your time to shine!

No really, I'm getting my butt kicked by an MS-SQL query that I can't seem to get to work.

What I am trying to do is search on a patient name; but also return patients who have a similar first or last name to the querying patient's last name. So "John Smith" can return anyone named "John Smith" or anyone who has a first or last name like "smith". If the a patient has multiple disease states, then combine those disease states into a single column. I have the following tables (though of course there are many more columns, but these are the most imortant):

Patient Table
PatientID    FirstName    LastName    UserIDFK
10000        John         Smith       1
10001        Miss         Smith       2
10002        Smith        Bomb        3
10003        Bobby        Smith       4
-- etc

DiseaseStateForUser
UserIDFK    DiseaseStateRefId
1           1
1           2
2           2
3           1
3           2
4           1

GlobalLookUp
RefId    Ref_Code
1        HIV
2        HEPC

The results I'm looking for are this:

PatientID    FirstName    LastName    DiseaseStates
10000        John         Smith       HIV|HEPC
10001        Miss         Smith       HEPC
10002        Smith        Bomb        HIV|HEPC
10003        Bobby        Smith       HIV

I've taken the examples from these questions (and countless others):

As well as from this blog post Emulating MySQL’s GROUP_CONCAT() Function in SQL Server 2005 I came up with the following SQL procedure

DECLARE 
    @PatientID          INT=null,           
    @FirstName          Varchar(15)= null,
    @LastName           Varchar(15)= 'Smith',
    @Name           Varchar(15) = 'John Smith',

Select
    Patient.First_Name,
    Patient.Last_Name, 
    patient.PatientID,      
    (select CAST(GlobalLookUp.Ref_Code + '|' as VARCHAR(MAX))
     from 
        TBL_PATIENT patient
        ,TBL_GBLLOOKUP GlobalLookUp
        ,TBL_DiseaseStateForUser DiseaseStateForUser
        -- Try and make a collection of all the PatientIDs
        -- that match the search criteria 
        -- so that only these are used to build
        -- the DiseaseStatesColumn
        ,(Select
            Patient.PatientID
                FROM TBL_PATIENT patient
                    ,TBL_SITEMASTER SiteMaster 
                    ,TBL_USERMASTER UserMaster
                    ,TBL_USERSINSITES UserInSites
                    ,TBL_GBLLOOKUP GlobalLookUp
                    ,TBL_DiseaseStateForUser DiseaseStateForUser
                WHERE   (((patient.[Last_Name] like @LastName + '%') OR (patient.[Last_Name] Like @Name + '%' ))
                            OR ((patient.[First_Name] Like @Name + '%' ))
                            OR  (patient.[First_Name] + ' ' + patient.[Last_Name] Like @Name + '%' ))
                    AND     UserMaster.User_Id = UserInSites.User_Id_FK
                    AND     UserInSites.Site_Id_FK = SiteMaster.Site_Id
                    AND     UserInSites.Is_Active = 'True'
                    AND     patient.[User_Id_FK] = UserMaster.[User_Id] 
                    AND     (DiseaseStateForUser.User_Id_FK = patient.User_Id_FK
                    AND     DiseaseStateForUser.DiseaseState_RefId_FK = GlobalLookUp.Ref_Id)
                    and     DiseaseStateForUser.Is_Active='True'
                    AND     patient.[Is_Active] = 'TRUE'
            group by Patient.PatientID) as PATIENTIDs
    where patient.PatientID = PATIENTIDs.PatientID  
            AND     (DiseaseStateForUser.User_Id_FK = patient.User_Id_FK
            AND     DiseaseStateForUser.DiseaseState_RefId_FK = GlobalLookUp.Ref_Id)
    For XML PATH('')) as MultiDiseaseState

FROM TBL_PATIENT patient, TBL_SITEMASTER SiteMaster ,TBL_USERMASTER UserMaster,TBL_USERSINSITES UserInSites, TBL_GBLLOOKUP GlobalLookUp, TBL_DiseaseStateForUser DiseaseStateForUser
WHERE   (((patient.[Last_Name] like @LastName + '%') OR (patient.[Last_Name] Like @Name + '%' ))
            or ((patient.[First_Name] Like @Name + '%' ))
            OR  (patient.[First_Name] + ' ' + patient.[Last_Name] Like @Name + '%' ))
    AND     patient.PatientID = patient.PatientID
    AND         UserMaster.User_Id = UserInSites.User_Id_FK
    AND     UserInSites.Site_Id_FK = SiteMaster.Site_Id
    AND     UserInSites.Is_Active = 'True'
    AND     patient.[User_Id_FK] = UserMaster.[User_Id] 
    AND     DiseaseStateForUser.User_Id_FK = patient.User_Id_FK
    AND     DiseaseStateForUser.DiseaseState_RefId_FK = GlobalLookUp.Ref_Id
    and     DiseaseStateForUser.Is_Active='True'
    AND     patient.[Is_Active] = 'TRUE'
group by PatientID, patient.First_Name, patient.Last_Name, GlobalLookUp.Ref_Code
order by PatientID

Unfortunately, this query nets me the following:

PatientID    FirstName    LastName    MultiDiseaseState
10000        John         Smith       HIV|HEPC|HEPC|HIV|HEPC|HIV
10001        Miss         Smith       HIV|HEPC|HEPC|HIV|HEPC|HIV
10002        Smith        Bomb        HIV|HEPC|HEPC|HIV|HEPC|HIV
10003        Bobby        Smith       HIV|HEPC|HEPC|HIV|HEPC|HIV

In other words, the select CAST(GlobalLookUp.Ref_Code + '|' as VARCHAR(MAX)) call is building up the MultiDiseaseState column with all of the disease states for ALL of the selected patients.

I know there is something fundamentally wrong with the most inner SELECT statement, but I'm having a hard time figuring out what it is and how to write the query so that it builds only the disease states for a given patient.

Kind of a long post, but are there any suggestions people can make given the code snippets I've provided?

Community
  • 1
  • 1
Emmanuel F
  • 1,125
  • 1
  • 15
  • 34
  • 1
    I had to laugh a little at your comment on not being sure if you want to bother reading everything I wrote. Frankly, I felt I was putting a lot, but I was worried if I tried to compress it more, it would be more confusing. @msucker0572's answer down below looks like it might actually work. The problem I have with your quick answer is that I'm not that well versed in SQL. But I will take the time to read up on those keywords you suggested. Thank you. – Emmanuel F Sep 28 '11 at 19:27

1 Answers1

2

You should be able to use the Stuff function (I think it's only on SQL 2005 and higher) to make this work, I took your example data and wrote a demonstration off of that

    SET NOCOUNT ON

CREATE TABLE #Patient
(
PatientID INT,
FirstName varchar(25),
LastName varchar(25),
UserIDFK INT
)
INSERT INTO #PATIENT SELECT 10000,'John','Smith',1 
INSERT INTO #PATIENT SELECT 10001,'Miss','Smith',2 
INSERT INTO #PATIENT SELECT 10002,'Smith','Bomb',3 
INSERT INTO #PATIENT SELECT 10003,'Bobby','Smith',4 

CREATE TABLE #DiseaseStateForUser 
(
UserIDFK int,
DiseaseStateRefId int
)

INSERT INTO #DiseaseStateForUser SELECT 1,1 
INSERT INTO #DiseaseStateForUser SELECT 1,2 
INSERT INTO #DiseaseStateForUser SELECT 2,2 
INSERT INTO #DiseaseStateForUser SELECT 3,1 
INSERT INTO #DiseaseStateForUser SELECT 3,2 
INSERT INTO #DiseaseStateForUser SELECT 4,1 

CREATE TABLE #GlobalLookUp
(
RefId int,
Ref_Code varchar(10)
)
INSERT INTO #GlobalLookUp SELECT 1,'HIV'
INSERT INTO #GlobalLookUp SELECT 2,'HEPC'


SELECT 
    PatientID,
    UserIDFK,
    FirstName,
    LastName,
    STUFF(
    (SELECT '|' + l.Ref_Code 
    FROM #DiseaseStateForUser u with (Nolock) 
    JOIN dbo.#GlobalLookUp l with (nolock)
        ON u.DiseaseStateRefId = l.RefId
    WHERE u.UserIDFK = p.UserIDFK FOR XML PATH('')
    )
    , 1, 1, '')
FROM #PATIENT p with (Nolock)
GROUP BY PatientID, FirstName, LastName, UserIDFK
msmucker0527
  • 5,164
  • 2
  • 22
  • 36
  • Well I'll be a dirty monkey's uncle. It's seriously that simple? This works exactly like I wanted it to. Why is the UserIDFK necessary in the select and the group by? I tried leaving it out, but it gave me an error. – Emmanuel F Sep 28 '11 at 19:31