Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 General SQL Server Forums
 New to SQL Server Programming
 Matching Comma Separated List

Author  Topic 

bielen
Yak Posting Veteran

97 Posts

Posted - 2008-06-07 : 21:09:49
I have the following SQL Query:

SELECT user_profiles.userFirstName, user_profiles.userInitial, user_profiles.userLastName, user_types.userTypeDesc, user_profiles.userOfficeIDs, user_profiles.userEmail
FROM user_profiles
INNER JOIN user_types ON user_types.userTypeID = user_types.userTypeID

The field userOfficeID contains a comma separated list of values such as "1,2" to identify that the user is in both the NJ and NY office.


Table office_locations
OfficeID officeState
1 NJ
2 NY
3 CT

I would like the output to be something similar to:

Name Office userOfficeIDs value
John Smith NJ 1
Mary Smith NJ/NY 1,2
Jim Smith NJ/CT 1,3
Mike Smith NY 2

Any direction would be appreciated.

Thanks

TG
Master Smack Fu Yak Hacker

6065 Posts

Posted - 2008-06-07 : 23:00:05
You should have an "association" table between your User_Profiles and Office_locations table. ie:
userLocations (userid, officeid, [locationtypeid?], [isPrimary?], primary key (userid, officeid))

that will be much more efficient. If that is not an option for you there are ways to do it...what version of sql server are you running?

Be One with the Optimizer
TG
Go to Top of Page

bielen
Yak Posting Veteran

97 Posts

Posted - 2008-06-07 : 23:26:30
I am using SQL Server 2005.

If I have an association table as you describe, can I still do it in a single query or would I have to have a separate query to select all the office records that match the office ID?

quote:
Originally posted by TG

You should have an "association" table between your User_Profiles and Office_locations table. ie:
userLocations (userid, officeid, [locationtypeid?], [isPrimary?], primary key (userid, officeid))

that will be much more efficient. If that is not an option for you there are ways to do it...what version of sql server are you running?

Be One with the Optimizer
TG

Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2008-06-08 : 05:12:31
quote:
Originally posted by bielen

I am using SQL Server 2005.

If I have an association table as you describe, can I still do it in a single query or would I have to have a separate query to select all the office records that match the office ID?

quote:
Originally posted by TG

You should have an "association" table between your User_Profiles and Office_locations table. ie:
userLocations (userid, officeid, [locationtypeid?], [isPrimary?], primary key (userid, officeid))

that will be much more efficient. If that is not an option for you there are ways to do it...what version of sql server are you running?

Be One with the Optimizer
TG




You can still retrieve them in a single query. Filtering on OfficeID will give you all records for particular office.
Go to Top of Page

bielen
Yak Posting Veteran

97 Posts

Posted - 2008-06-08 : 07:30:53
I've tried getting it working with a cross join filtering on OfficeID:

SELECT user_profiles.userFirstName, user_profiles.userInitial, user_profiles.userLastName,
user_types.userTypeDesc, user_profiles.userOfficeIDs, user_profiles.userEmail,
office_locations.officeState
FROM user_profiles INNER JOIN
user_types ON user_types.userTypeID = user_profiles.userType CROSS JOIN
office_locations
WHERE (CAST(office_locations.officeID AS VARCHAR(6)) IN (user_profiles.userOfficeIDs))
ORDER BY user_profiles.userLastName

All the records are retrieved, but I'm only getting a single office location in the officeState field. I wan tto be able to get multiple states comma delimited in the office field (i.e. NY, NJ). If I remove the where clause, I retrieve all the offices, but they are on separate lines. How do I put all the officeState values into a single comma delimited field?

Thank you for any advice.


quote:
Originally posted by visakh16

quote:
Originally posted by bielen

I am using SQL Server 2005.

If I have an association table as you describe, can I still do it in a single query or would I have to have a separate query to select all the office records that match the office ID?

quote:
Originally posted by TG

You should have an "association" table between your User_Profiles and Office_locations table. ie:
userLocations (userid, officeid, [locationtypeid?], [isPrimary?], primary key (userid, officeid))

that will be much more efficient. If that is not an option for you there are ways to do it...what version of sql server are you running?

Be One with the Optimizer
TG




You can still retrieve them in a single query. Filtering on OfficeID will give you all records for particular office.

Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2008-06-08 : 08:20:28
Are you using SQL 2005?
Go to Top of Page

bielen
Yak Posting Veteran

97 Posts

Posted - 2008-06-08 : 08:32:07
quote:
Originally posted by visakh16

Are you using SQL 2005?



Yes
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2008-06-08 : 08:54:49
quote:
Originally posted by bielen

quote:
Originally posted by visakh16

Are you using SQL 2005?



Yes


What are your current table structures? Is userOfficeIDs field in user_profiles storing comma delimited IDs? ALso you could give some sample data from each table?
Go to Top of Page

bielen
Yak Posting Veteran

97 Posts

Posted - 2008-06-08 : 10:56:07
quote:
Originally posted by visakh16

quote:
Originally posted by bielen

quote:
Originally posted by visakh16

Are you using SQL 2005?



Yes


What are your current table structures? Is userOfficeIDs field in user_profiles storing comma delimited IDs? ALso you could give some sample data from each table?



Yes. The officeUserIDs has a commaDelimited list of IDs of office locations. I want to be able join in the office state values (NY, NJ, CT) to replace the IDs.

I have three tables:

user_profiles
-------------
userID, userFirstName, userInitial, UserLastName, UserType, userOfficeIDs, userEmail
1 John J Smith 1 1 emailAddress
2 Mary J Smith 2 1,2 emailAddress
3 Jack J Smith 2 1,3 emailAddress

user_types
----------
userTypeID, userTypeDesc
1 Manager
2 Director
3 VP

office_locations
----------
officeID, officeState
1 NJ
2 NY
3 CT

Once retrieved, I want the final output to appear as:

userID, userFirstName, userInitial, UserLastName, UserTypeDesc, officeState, userEmail
1 John J Smith Manager NJ emailAddress
2 Mary J Smith Director NJ, NY emailAddress
3 Jack J Smith Director NJ, CT emailAddress

Thanks
Go to Top of Page

bielen
Yak Posting Veteran

97 Posts

Posted - 2008-06-08 : 17:11:14
Anyone have any ideas? I'm kind of stuck unless I do some workaround.
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2008-06-09 : 01:38:18

declare @user_profiles table
(userID int, userFirstName varchar(100), userInitial char(1), UserLastName varchar(100), UserType int, userOfficeIDs varchar(100), userEmail varchar(100))
INSERT INTO @user_profiles
SELECT 1, 'John', 'J', 'Smith', 1, '1', 'emailAddress'
UNION ALL
SELECT 2, 'Mary', 'J', 'Smith', 2, '1,2', 'emailAddress'
UNION ALL
SELECT 3, 'Jack', 'J', 'Smith' ,2, '1,3', 'emailAddress'

SELECT * FROm @user_profiles t
CROSS APPLY ParseValues(t.userOfficeIDs) b

declare @user_types table

(userTypeID int, userTypeDesc varchar(100))
insert into @user_types
SELECT 1, 'Manager'
UNION ALL
SELECT 2, 'Director'
UNION ALL
SELECT 3, 'VP'

declare @office_locations table
(officeID int,
officeState varchar(100)
)
insert into @office_locations
SELECT 1, 'NJ'
UNION ALL
SELECT 2, 'NY'
UNION ALL
SELECT 3, 'CT'
;
WIth CTE(userID,userFirstName,UserInitial,UserLastName,UserType,userEmail,Val) AS
(
SELECT t.userID,t.userFirstName,t.UserInitial,t.UserLastName,t.UserType,t.userEmail,b.Val FROm @user_profiles t
CROSS APPLY ParseValues(t.userOfficeIDs)b
)


SELECT DISTINCT r.userID,userFirstName,UserInitial,UserLastName,userEmail,userTypeDesc,left(ol.officelist,len(ol.officelist)-1)
FROM
(SELECT DISTINCT userID,userFirstName,UserInitial,UserLastName,UserType,userEmail,userTypeDesc,Val FROM CTE m
INNER JOIN @user_types ut
ON ut.userTypeID=m.UserType)r
CROSS APPLY (SELECT ol.officeState + ',' AS [text()]
FROM CTE m1
INNER JOIN @office_locations ol
ON ol.officeID=m1.Val
WHERE m1.userID=r.userID
FOR XML PATH(''))ol(officelist)



output
userID userFirstName UserInitial UserLastName userEmail userTypeDesc OfficeLocations
----------- -------------------- ----------- -------------------- -------------------- -------------------- --------------------
1 John J Smith emailAddress Manager NJ
2 Mary J Smith emailAddress Director NJ,NY
3 Jack J Smith emailAddress Director NJ,CT
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2008-06-09 : 01:48:50
Also it would be much easier if you could use a seperate table to store the office ids rather then storing it as comma seperated list inside user_profiles table istself.
Go to Top of Page

bielen
Yak Posting Veteran

97 Posts

Posted - 2008-06-09 : 20:18:30
quote:
Originally posted by visakh16

Also it would be much easier if you could use a seperate table to store the office ids rather then storing it as comma seperated list inside user_profiles table istself.



viskah16:

Thank you for your detailed reply. As per your advice and further research on the web, I have created a separate table to store the officeID.

I've updated the query as follows:

SELECT user_profiles.userFirstName, user_profiles.userInitial, user_profiles.userLastName,
user_types.userTypeDesc, user_profiles.userEmail, user_location_index.officeID
FROM user_profiles INNER JOIN
user_types ON user_types.userTypeID = user_profiles.userType INNER JOIN
user_location_index ON user_profiles.userID IN (user_location_index.userID)
ORDER BY user_profiles.userLastName

How do I now link in the office state location to actually display the respective state/states. I tried an INNER JOIN on officeID to officeLocations, but didn't achieve the desired results. It displayed all states for each entry.

user_profiles
-------------
userID, userFirstName, userInitial, UserLastName, UserType, userEmail
1 John, J, Smith, 1, emailAddress
2 Mary, J, Smith, 2, emailAddress
3 Jack, J, Smith, 2, emailAddress

user_types
----------
userTypeID, userTypeDesc
1 Manager
2 Director
3 VP

office_locations
----------
officeID, officeState
1 NJ
2 NY
3 CT

user_location_index
ID,userID,officeID
1,1,1
2,2,1
3,2,2
4,3,1
5,3,3

Thanks again for your help. The learning experience is appreciated.
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2008-06-10 : 00:25:52
quote:
Originally posted by bielen

quote:
Originally posted by visakh16

Also it would be much easier if you could use a seperate table to store the office ids rather then storing it as comma seperated list inside user_profiles table istself.



viskah16:

Thank you for your detailed reply. As per your advice and further research on the web, I have created a separate table to store the officeID.

I've updated the query as follows:

SELECT user_profiles.userFirstName, user_profiles.userInitial, user_profiles.userLastName,
user_types.userTypeDesc, user_profiles.userEmail, user_location_index.officeID
FROM user_profiles INNER JOIN
user_types ON user_types.userTypeID = user_profiles.userType INNER JOIN
user_location_index ON user_profiles.userID IN (user_location_index.userID)
ORDER BY user_profiles.userLastName

How do I now link in the office state location to actually display the respective state/states. I tried an INNER JOIN on officeID to officeLocations, but didn't achieve the desired results. It displayed all states for each entry.

user_profiles
-------------
userID, userFirstName, userInitial, UserLastName, UserType, userEmail
1 John, J, Smith, 1, emailAddress
2 Mary, J, Smith, 2, emailAddress
3 Jack, J, Smith, 2, emailAddress

user_types
----------
userTypeID, userTypeDesc
1 Manager
2 Director
3 VP

office_locations
----------
officeID, officeState
1 NJ
2 NY
3 CT

user_location_index
ID,userID,officeID
1,1,1
2,2,1
3,2,2
4,3,1
5,3,3

Thanks again for your help. The learning experience is appreciated.


You're welcome . We are happy to help you always.
Go to Top of Page

bielen
Yak Posting Veteran

97 Posts

Posted - 2008-06-10 : 12:03:27
I almost have everything working:

SELECT user_profiles.userID, user_profiles.userFirstName, user_profiles.userLastName, user_types.userTypeDesc, user_locations.locationDesc FROM user_profiles INNER JOIN user_types ON user_profiles.userType = user_types.userTypeID INNER JOIN user_location_index ON user_profiles.userID = user_location_index.userID INNER JOIN user_locations ON user_location_index.locationID = user_locations.locationID

The only issue is that my output comes out as separate rows:

userid, userFirstName, UserLastName, UserTypeDesc, locationDesc
1,John,Adams,Manager,NJ
1,John,Adams,Manager,NY
2,Mary,Smith,Director,CT
3,Mike,Jones,Director,FL
4,Bill,Murphy,VP,NJ
4,Bill,Murphy,VP,NY
4,Bill,Murphy,VP,FL

The issue relateds to my original comma delimited list. I want to only have a single record for each user with multiple locations shown. (John Adamin in NJ and NY).

I've read about COALESCE, but not sure how i would apply it to this situation? Do I need a view?

Thanks

Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2008-06-10 : 12:34:00
Try like this:-
SELECT user_profiles.userID, 
user_profiles.userFirstName,
user_profiles.userLastName,
user_types.userTypeDesc,
LEFT(ll.LocationList,LEN(ll.LocationList)-1) AS Locations
FROM user_profiles
INNER JOIN user_types
ON user_profiles.userType = user_types.userTypeID
INNER JOIN user_location_index
ON user_profiles.userID = user_location_index.userID
CROSS APPLY(
SELECT locationDesc + ',' AS [text()]
FROM user_locations
WHERE locationID= user_location_index.locationID
FOR XML PATH(''))ll(LocationList)
Go to Top of Page

bielen
Yak Posting Veteran

97 Posts

Posted - 2008-06-10 : 18:53:20
quote:
Originally posted by visakh16

Try like this:-
SELECT user_profiles.userID, 
user_profiles.userFirstName,
user_profiles.userLastName,
user_types.userTypeDesc,
LEFT(ll.LocationList,LEN(ll.LocationList)-1) AS Locations
FROM user_profiles
INNER JOIN user_types
ON user_profiles.userType = user_types.userTypeID
INNER JOIN user_location_index
ON user_profiles.userID = user_location_index.userID
CROSS APPLY(
SELECT locationDesc + ',' AS [text()]
FROM user_locations
WHERE locationID= user_location_index.locationID
FOR XML PATH(''))ll(LocationList)




Hello:

I tried the script and understand the logic, but still get the same results. If a user has an office in two locations, it displays two separate records. Should the script written as is display a single record for each user with a comma delimtied listing in LocationList?
Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2008-06-10 : 23:55:21
i think it should be like this seeing your table DDL

SELECT user_profiles.userID, 
user_profiles.userFirstName,
user_profiles.userLastName,
user_types.userTypeDesc,
LEFT(ll.LocationList,LEN(ll.LocationList)-1) AS Locations
FROM user_profiles
INNER JOIN user_types
ON user_profiles.userType = user_types.userTypeID
CROSS APPLY(
SELECT ul.locationDesc + ',' AS [text()]
FROM user_locations ul
INNER JOIN user_location_index uli
ON ul.locationID= uli.locationID
WHERE uli.userID =user_profiles.userID
FOR XML PATH(''))ll(LocationList)
Go to Top of Page

bielen
Yak Posting Veteran

97 Posts

Posted - 2008-06-11 : 09:07:56
visakh16:

Thank you. I now have it working exactly the way I want. I'm going to research the use of the CROSS APPLY with XML in SQL 2005. This was the first time I had a need to use the functionality.

Thanks

quote:
Originally posted by visakh16

i think it should be like this seeing your table DDL

SELECT user_profiles.userID, 
user_profiles.userFirstName,
user_profiles.userLastName,
user_types.userTypeDesc,
LEFT(ll.LocationList,LEN(ll.LocationList)-1) AS Locations
FROM user_profiles
INNER JOIN user_types
ON user_profiles.userType = user_types.userTypeID
CROSS APPLY(
SELECT ul.locationDesc + ',' AS [text()]
FROM user_locations ul
INNER JOIN user_location_index uli
ON ul.locationID= uli.locationID
WHERE uli.userID =user_profiles.userID
FOR XML PATH(''))ll(LocationList)


Go to Top of Page

visakh16
Very Important crosS Applying yaK Herder

52326 Posts

Posted - 2008-06-11 : 10:01:56
quote:
Originally posted by bielen

visakh16:

Thank you. I now have it working exactly the way I want. I'm going to research the use of the CROSS APPLY with XML in SQL 2005. This was the first time I had a need to use the functionality.

Thanks

quote:
Originally posted by visakh16

i think it should be like this seeing your table DDL

SELECT user_profiles.userID, 
user_profiles.userFirstName,
user_profiles.userLastName,
user_types.userTypeDesc,
LEFT(ll.LocationList,LEN(ll.LocationList)-1) AS Locations
FROM user_profiles
INNER JOIN user_types
ON user_profiles.userType = user_types.userTypeID
CROSS APPLY(
SELECT ul.locationDesc + ',' AS [text()]
FROM user_locations ul
INNER JOIN user_location_index uli
ON ul.locationID= uli.locationID
WHERE uli.userID =user_profiles.userID
FOR XML PATH(''))ll(LocationList)





You're welcome
Go to Top of Page
   

- Advertisement -