How to parse out a column in sql with multiple values - sql

I have a column in a sql server table named [City_St_Zip] that contains records that look like this
Dallas, TX 12345
What I would like to do is separate the column into three different columns (i.e. City, State and Zip)
like this:
Dallas
TX
12345
I am not sure how to go about this in SQL
I have tried the following
DECLARE #X NVARCHAR(100),
DECLARE #T NVARCHAR(100),
SELECT
#X = [City_St_Zip],
#T = [NewDivision]
FROM
dbo.Invoice
CROSS APPLY STRING_SPLIT(#X, ',');
This yielded 0 results so I am pretty sure I did that incorrectly
Any suggestions? I am using SQL Server 2019
EDIT:
I also tried this which is closer to what I want
SELECT
value
FROM
dbo.Invoice
CROSS APPLY STRING_SPLIT([City_St_Zip], ',');
That gives me a result set of:
Dallas
TX 12345
So I guess this is convoluted and needs both a comma and a space delimiter. Would I just put the value through another STRING_SPLIT?

SQL Server has poor string processing support. And, string_split() is not guaranteed to keep the values in order. And string searches are dangerous -- think New York, New York.
So, a brute force method:
select left(col, charindex(',', col) - 1) as city,
substring(col, charindex(',', col) + 2, 2) as state,
right(col, 5) as zipcode
Here is a db<>fiddle.

If you want to use STRING_SPLIT then this will work without variables.
Sample data:
create table dbo.Invoice
(
id int identity(1,1) primary key,
[City_St_Zip] nvarchar(100)
);
insert into dbo.Invoice
([City_St_Zip]) values
('Dallas, TX 12345'),
('Fort Worth, TX 12345')
GO
2 rows affected
Query:
SELECT inv.*, a.*
FROM dbo.Invoice inv
OUTER APPLY
(
SELECT
[1] AS [City],
LTRIM(LEFT([2], 3)) AS [State],
TRIM(SUBSTRING([2],4,LEN([2]))) AS [Zip]
FROM
( SELECT spl.value
, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS rn
FROM STRING_SPLIT(inv.[City_St_Zip],',') spl
) s
PIVOT (MAX(value) FOR rn IN ([1],[2])) p
) a;
Result:
id | City_St_Zip | City | State | Zip
-: | :------------------- | :--------- | :---- | :----
1 | Dallas, TX 12345 | Dallas | TX | 12345
2 | Fort Worth, TX 12345 | Fort Worth | TX | 12345
db<>fiddle here
Extra:
Using the XML type, this SQL will also work in an earlier version like Sql Server 2012.
SELECT inv.*
, a.City
, RTRIM(LEFT(a.StateZip, CHARINDEX(' ',a.StateZip))) AS State
, LTRIM(SUBSTRING(a.StateZip, CHARINDEX(' ',a.StateZip),LEN(a.StateZip))) AS Zip
FROM dbo.Invoice inv
OUTER APPLY
(
SELECT X.x AS CityStateZipXml
, X.x.value('/x[1]','nvarchar(max)') AS City
, LTRIM(X.x.value('/x[2]','nvarchar(max)')) AS StateZip
FROM (
SELECT CAST(CONCAT('<x>', REPLACE(inv.[City_St_Zip],',','</x><x>'),'</x>') AS XML)
) AS X(x)
) a;

* Updated as per SQL Server*
create table ctry
(
city_st_zip nvarchar(100)
);
insert into ctry values('Dallas, TX 12345');
--SQL USED--
SELECT
LEFT([city_st_zip], CHARINDEX(',', [city_st_zip]) - 1) AS [City],
SUBSTRING([city_st_zip], CHARINDEX(',', [city_st_zip]) + 2, 2) as [State],
RIGHT([city_st_zip], CHARINDEX(' ', [city_st_zip]) - 2) AS [Zip]
FROM ctry;
--Result--
City State Zip
Dallas TX 12345

Related

I need help parsing an HL7 string with TSQL

I have a column in a table that looks like this
Name
WALKER^JAMES^K^^
ANDERSON^MICHAEL^R^^
HUFF^CHRIS^^^
WALKER^JAMES^K^^
SWEARINGEN^TOMMY^L^^
SMITH^JOHN^JACCOB^^
I need to write a query that looks like this
Name
FirstName
LastName
MiddleName
WALKER^JAMES^K^^
JAMES
WALKER
K
ANDERSON^MICHAEL^R^^
MICHAEL
ANDERSON
R
HUFF^CHRIS^^^
CHRIS
HUFF
BUTLER^STEWART^M^^
STEWART
BUTLER
M
SWEARINGEN^TOMMY^L^^
TOMMY
SWEARINGEN
L
SMITH^JOHN^JACCOB^^
JOHN
SMITH
JACCOB
I need help generating the LastName column.
This is what I've tried so far
SUBSTRING
(
--SEARCH THE NAME COLUMN
Name,
--Starting after the first '^'
CHARINDEX('^', Name) + 1 ),
--Index of second ^ minus the index of the first ^
(CHARINDEX('^', PatientName, CHARINDEX('^', PatientName) +1)) - (CHARINDEX('^', PatientName))
)
This produces:
Invalid length parameter passed to the LEFT or SUBSTRING function.
I know this can work because if I change the minus sign to a plus sign it performs as expected.
It produces the right integer.
Where am I going wrong? Is there a better way to do this?
If you are using the latest SQL Server versions 2016 13.x or higher, you can maximize the use of string_split function with ordinal (position).
declare #strTable table(sqlstring varchar(max))
insert into #strTable (sqlstring) values ('WALKER^JAMES^K^^')
insert into #strTable (sqlstring) values ('ANDERSON^MICHAEL^R^^')
insert into #strTable (sqlstring) values ('HUFF^CHRIS^^^')
insert into #strTable (sqlstring) values ('SWEARINGEN^TOMMY^L^^');
with tmp as
(select value s, Row_Number() over (order by (select 0)) n from #strTable
cross apply String_Split(sqlstring, '^', 1))
select t2.s as FirstName, t1.s as LastName, t3.s as MiddleInitial from tmp t1
left join tmp t2 on t2.n-t1.n = 1
left join tmp t3 on t3.n-t1.n = 2
where t1.n = 1 or t1.n % 5 = 1
I recommend SUBSTRING() as it will perform the best. The challenge with SUBSTRING is it's hard to account to keep track of the nested CHARDINDEX() calls so it's better to break the calculation into pieces. I use CROSS APPLY to alias each "^" found and start from there to search for the next. Also allows to do NULLIF() = 0, so if it can't find the "^", it just returns a NULL instead of erroring out
Parse Delimited String using SUBSTRING() and CROSS APPLY
DROP TABLE IF EXISTS #Name
CREATE TABLE #Name (ID INT IDENTITY(1,1) PRIMARY KEY,[Name] varchar(255))
INSERT INTO #Name
VALUES ('WALKER^JAMES^K^^')
,('ANDERSON^MICHAEL^R^^')
,('HUFF^CHRIS^^^')
,('SWEARINGEN^TOMMY^L^^');
SELECT ID
,A.[Name]
,LastName = NULLIF(SUBSTRING(A.[Name],0,idx1),'')
,FirstName = NULLIF(SUBSTRING(A.[Name],idx1+1,idx2-idx1-1),'')
,MiddleInitial = NULLIF(SUBSTRING(A.[Name],idx2+1,idx3-idx2-1),'')
FROM #Name AS A
CROSS APPLY (SELECT idx1 = NULLIF(CHARINDEX('^',[Name]),0)) AS B
CROSS APPLY (SELECT idx2 = NULLIF(CHARINDEX('^',[Name],idx1+1),0)) AS C
CROSS APPLY (SELECT idx3 = NULLIF(CHARINDEX('^',[Name],idx2+1),0)) AS D

SQL server query to search and stuff multiple rows

I have table employee_table which is like this
org employeeid (int) firstname lastname
1234 56788934 Suresh Raina
1234 56793904 Virat Kohli
then i have project_table which is like this
Project members (varchar)
A123 56788934,56793900
Now i need to fetch corresponding names of employees and stuff in a single row like this.
Project members (varchar)
A123 Suresh Raina, Virat Kohli
I have written below query which is not working. please help.
SELECT project,
(
SELECT message_text = Stuff(
(
SELECT ', ' + Concat(firstname,' ',lastname)
FROM employee_table t1
WHERE t1.org = t2.org
AND CONVERT(VARCHAR,t1.userid) IN (Concat('''',Replace(pt.members,',',''','''),'''')) --adding single quotes at start and end of each number
FOR xml path ('')) , 1, 1, '')
FROM employee_table t2
WHERE t2.userid IN
group BY org;) FROM project_table pt
Here is a solution for SQL Server 2017 onwards.
It is using a pair of handy functions available in SQL Server 2017:
STRING_SPLIT()
STRING_AGG()
Method #2 covers solution for SQL Server 2008 onwards.
SQL
-- DDL and sample data population, start
DECLARE #employee TABLE (org INT, employeeid INT, firstname VARCHAR(20), lastname VARCHAR(30));
INSERT INTO #employee (org, employeeid, firstname, lastname) VALUES
(1234, 56788934, 'Suresh', 'Raina'),
(1234, 56793904, 'Virat', 'Kohli');
DECLARE #project TABLE (project CHAR(4), members VARCHAR(MAX));
INSERT INTO #project (project, members) VALUES
('A123', '56788934,56793904');
-- DDL and sample data population, end
-- Method #1, SQL Server 2017 onwards
SELECT p.project, STRING_AGG(CONCAT(e.firstname, SPACE(1), e.lastname), ', ') AS members
FROM #project AS p CROSS APPLY STRING_SPLIT(members, ',') AS s
INNER JOIN #employee AS e ON s.value = e.employeeid
GROUP BY p.project;
-- Method #2, SQL Server 2008 onwards
DECLARE #separator CHAR(1) = ',';
;WITH rs AS
(
SELECT *
, TRY_CAST('<root><r><![CDATA[' +
REPLACE(members, #separator, ']]></r><r><![CDATA[') + ']]></r></root>' AS XML) AS xmldata
FROM #project
), cte AS
(
SELECT project
, e.*
FROM rs CROSS APPLY xmldata.nodes('/root/r/text()') AS t(c)
INNER JOIN #employee AS e ON c.value('.','INT') = e.employeeid
)
SELECT project
, STUFF((SELECT #separator + CAST(CONCAT(o.firstname, SPACE(1), o.lastname) AS VARCHAR(30)) AS [text()]
FROM cte AS O
WHERE O.project = C.project
FOR XML PATH('')), 1, 1, NULL) AS Members
FROM cte AS c
GROUP BY project;
Output
+---------+---------------------------+
| project | members |
+---------+---------------------------+
| A123 | Suresh Raina, Virat Kohli |
+---------+---------------------------+

SQL Server 2012 Convert several comma delimited values to table rows/columns

Currently, I have a table that is storing historical data in the following fashion. I have no control over this server or how the data is stored.
ID | FName | LName |Stuff| More
--------+---------+---------+-----+------
1,2,3,4 | j,p,g,r | l,m,h,s | ,,, | a,,b,
I need to get this data into a result set so that it is in the following format:
ID | FName | LName |Stuff| More
--------+---------+---------+-----+------
1 | j | l | | a
2 | p | m | |
3 | g | h | | b
4 | r | s | |
I would like to avoid using a function as I am unsure of the access I will have to the servers in other environments. I have tried using xml with cross apply, which I can get to work for a singular field, but I cannot seem to get the full table to work.
Any suggestions would be greatly appreciated,
Thanks
~JM
It can be done by recursive query
;WITH CTE(ID, ID_tmp, FName, FName_tmp, LName, LName_tmp, Stuf, Stuf_tmp, more, more_tmp)
AS
(
SELECT CAST(LEFT(ID, CHARINDEX(',',ID+',')-1) AS NVARCHAR(50)) ID,
STUFF(ID, 1, CHARINDEX(',',ID+','), '') ID_tmp,
CAST(LEFT(FName, CHARINDEX(',',FName+',')-1) AS NVARCHAR(50)) FName,
STUFF(FName, 1, CHARINDEX(',',FName+','), '') ID_tmp,
CAST(LEFT(LName, CHARINDEX(',',LName+',')-1) AS NVARCHAR(50)) LName,
STUFF(LName, 1, CHARINDEX(',',LName+','), '') LName_tmp,
CAST(LEFT(Stuf, CHARINDEX(',',Stuf+',')-1) AS NVARCHAR(50)) Stuf,
STUFF(Stuf, 1, CHARINDEX(',',Stuf+','), '') Stuf_tmp,
CAST(LEFT(more, CHARINDEX(',',more+',')-1) AS NVARCHAR(50)) more,
STUFF(more, 1, CHARINDEX(',',more+','), '') more_tmp
FROM TAB
UNION ALL
SELECT CAST(LEFT(ID_tmp, CHARINDEX(',',ID_tmp+',')-1) AS NVARCHAR(50)) ID,
STUFF(ID_tmp, 1, CHARINDEX(',',ID_tmp+','), '') ID_tmp,
CAST(LEFT(FName_tmp, CHARINDEX(',',FName_tmp+',')-1) AS NVARCHAR(50)) FName,
STUFF(FName_tmp, 1, CHARINDEX(',',FName_tmp+','), '') FName_tmp,
CAST(LEFT(LName_tmp, CHARINDEX(',',LName_tmp+',')-1) AS NVARCHAR(50)) LName,
STUFF(LName_tmp, 1, CHARINDEX(',',LName_tmp+','), '') LName_tmp,
CAST(LEFT(Stuf_tmp, CHARINDEX(',',Stuf_tmp+',')-1) AS NVARCHAR(50)) Stuf,
STUFF(Stuf_tmp, 1, CHARINDEX(',',Stuf_tmp+','), '') Stuf_tmp,
CAST(LEFT(more_tmp, CHARINDEX(',',more_tmp+',')-1) AS NVARCHAR(50)) more,
STUFF(more_tmp, 1, CHARINDEX(',',more_tmp+','), '') more_tmp
FROM CTE
WHERE ID_tmp > ''
)
SELECT ID, FName , LName, stuf, more
FROM CTE
If, you want to avoid use of UDF, then XML nodes() method still able to help you by using multiple CTE approach.
WITH cteId AS
(
SELECT Ids.value('.', 'INT') Id FROM
(
SELECT
cast('<x>'+replace(Id, ',', '</x><x>')+'</x>' as xml) as Id
FROM table t
)a CROSS APPLY Id.nodes ('/x') as split(Ids)
), ctefname AS
(
SELECT
row_number() over (order by (select 1)) Seq,
FNames.value('.', 'varchar') FNames FROM
(
SELECT
cast('<x>'+replace(FName, ',', '</x><x>')+'</x>' as xml) as FName
FROM table t
)a CROSS APPLY FName.nodes ('/x') as split(FNames)
), cteLname AS
(
SELECT
row_number() over (order by (select 1)) Seq,
LNames.value('.', 'varchar') LNames FROM
(
SELECT
cast('<x>'+replace(LName, ',', '</x><x>')+'</x>' as xml) as LName
FROM table t
)a CROSS APPLY LName.nodes ('/x') as split(LNames)
), ...
SELECT
id.Id, fn.FNames, ln.LNames, ...
FROM cteId id
INNER JOIN ctefname fn on fn.Seq = id.Id
INNER JOIN cteLname ln on ln.Seq = id.Id
...

SQL Server: Merge two values with regexp

I am using an SQL Server database and have these following tables
Table "Data"
--------------------------------------------------------------------------------------------------|
| Id |col_1_type | col_1_name | col_2_type | col_2_name | col_3_type | col_3_name |
--------------------------------------------------------------------------------------------------|
| 1 |KI | Inflation Rate | KI | Currency Rate | MI | Government Spending |
--------------------------------------------------------------------------------------------------|
And i just want to make my result to be like this:
+----+------------------------+
| Id | results |
+----+------------------------+
| 1 | KI-Inflation Rate |
| 2 | KI-Currency Rate |
| 3 | MI-Government Spending |
+----+------------------------+
The column name is mandatory though, thats what made it complicated i guess?
i know you can merge 2 values or concatenate it, but i'm stuck on the column name such as col_1_name and col_2_type. Do i need to use regexp maybe?
Please try this-
select ROW_NUMBER() OVER (ORDER BY (select null)) id , results
from
(
SELECT CONCAT(col_1_type,'-',col_1_name) results
FROM [Data]
UNION ALL
SELECT CONCAT(col_2_type,'-',col_2_name)
FROM Data
UNION ALL
SELECT CONCAT(col_3_type,'-',col_3_name)
FROM Data
)o
Or this also
SELECT Id,results
FROM Data
CROSS apply
(VALUES (CONCAT(col_1_type,'-',col_1_name),1),(CONCAT(col_2_type,'-',col_2_name),2)
,(CONCAT(col_3_type,'-',col_3_name) ,3) ) cs (results,Id)
I would use of cross apply with the help of CTE and stuff()
;with cte as
(
select a.* from table t
cross apply (
values
(t.col_1_type, 'col_1'),
(t.col_1_name, 'col_1'),
(t.col_2_type, 'col_2'),
(t.col_2_name, 'col_2'),
(t.col_3_type, 'col_3'),
(t.col_3_name, 'col_3')
) a(name, id)
)
select distinct stuff(
(select '-'+name from cte where id= c.id for xml path('')),
1,1, ''
) [Results],
from cte c
EDIT :
Not sure about Id column but my guess that could be resolved by using ranking function
select row_number() over (order by (select 1)) Id,
cc.Results from
(
select distinct stuff(
(select '-'+id from cte where name = c.name for xml path('')),
1,1, ''
) [Results]
from cte c
) cc
Result :
Id Results
1 KI-Currency Rate
2 KI-Inflation Rate
3 MI-Government Spending
Sample data
IF OBJECT_ID('tempdb..#t') iS NOT NULL
DROP TABLE #t
IF OBJECT_ID('dbo.temp','U') iS NOT NULL
DROP TABLE temp
;With CTe(
Id ,col_1_type , col_1_name, col_2_type , col_2_name, col_3_type , col_3_name )
AS
(
SELECT 1,'KI','Inflation Rate','KI','Currency Rate','MI','Government Spending'
)
SELECT * INTO temp FROM CTe
Using Dynamic sql
DECLARE #Sqlstring nvarchar(max)
,#SQlQuery nvarchar(max)
;WITH cte
AS
(
SELECT COLUMN_NAME ,
((ROW_NUMBER()OVER(ORDER BY (SELECT NULL))-1)/2 )+1 AS BatchSeq
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='temp' AND COLUMN_NAME<>'Id'
)
SELECT #Sqlstring=STUFF((SELECT ', '+COLUMN_NAME FROM
(
SELECT DISTINCT '('+STUFF((SELECT ', '+COLUMN_NAME
FROM cte i
WHERE i.BatchSeq=o.BatchSeq FOR XML PATH ('')),1,1,'') +')' AS COLUMN_NAME
FROM cte o
)dt
FOR XML PATH ('')),1,1,'')
SET #SQlQuery='
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS ID,
CONCAT(col_type,''-'',Col_names) AS Result
FROM Temp
CROSS APPLY ( VALUES '+#Sqlstring+') dt(col_type,Col_names)'
PRINT #SQlQuery
EXEC(#SQlQuery)
Result
ID Result
-----------------------
1 KI-Inflation Rate
2 KI-Currency Rate
3 MI-Government Spending
Try like this
select (column1 || ' '|| column2) from table;
or
SELECT tablename.col_1_type + ' ' + tablename.col_1_name AS results;

Trouble combining rows into one column using CAST(

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):
Is there a way to create a SQL Server function to “join” multiple
rows from a subquery into a single delimited
field?
Simulating group_concat MySQL function in MS SQL Server
2005?
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?
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