views:

274

answers:

8

I know I am sounding dumb but I really need help on this.

I have a Table (let's say Meeting) which Contains a column Participants. The Participants dataType is varchar(Max) and it stores Participant's Ids in comma separated form like 1,2.

Now my problem is I am passing a parameter called @ParticipantsID in my Stored Procedure and want to do something like this:

Select Participants from Meeting where Participants in (@ParticipantsID)

Unfortunately I am missing something crucial here.

Can some one point that out?

+1  A: 

If I understand your question correctly, you are trying to pass in a comma separated list of participant ids and see if it is in your list. This link lists several ways to do such a thing"

[http://vyaskn.tripod.com/passing_arrays_to_stored_procedures.htm][1]

codezy.blogspot.com

Codezy
In my Case the Column called Participants is having CSV and I am passing only a single ParticipantsID
in that case it should work I think if you flip your clause around:Select Participants from Meeting where @ParticipantsID in Participants
Codezy
A: 

If you store the participant ids in a comma-separated list (as text) in the database, you cannot easily query it (as a list) using SQL. You would have to resort to string-operations.

You should consider changing your schema to use another table to map meetings to participants:

create table meeting_participants (
   meeting_id integer not null , -- foreign key
   participant_id integer not null
);

That table would have multiple rows per meeting (one for each participant). You can then query that table for individual participants, or number of participants, and such.

Thilo
A: 

If participants is a separate data type you should be storing it as a child table of your meeting table. e.g.

  • MEETING
    • PARTICIPANT 1
    • PARTICIPANT 2
    • PARTICIPANT 3

Each participant would hold the meeting ID so you can do a query

SELECT * FROM participants WHERE meeting_id = 1

However, if you must store a comma separated list (for some external reason) then you can do a string search to find the appropriate record. This would be a very inefficient way to do a query though.

Richard Nichols
A: 

That is not the best way to store the information you have.

If it is all you have got then you need to be doing a contains (not an IN). The best answer is to have another table that links Participants to Meetings.

Try SELECT Meeting, Participants FROM Meeting CONTAINS(Participants, @ParticipantId)

Brody
+3  A: 

I've been there before... I changed the DB design to have one record contain a single reference to the other table. If you can't change your DB structures and you have to live with this, I found this solution on CodeProject.

New Function

IF EXISTS(SELECT * FROM sysobjects WHERE ID = OBJECT_ID(’UF_CSVToTable’))
 DROP FUNCTION UF_CSVToTable
GO

CREATE FUNCTION UF_CSVToTable
(
 @psCSString VARCHAR(8000)
)
RETURNS @otTemp TABLE(sID VARCHAR(20))
AS
BEGIN
 DECLARE @sTemp VARCHAR(10)

 WHILE LEN(@psCSString) > 0
 BEGIN
  SET @sTemp = LEFT(@psCSString, ISNULL(NULLIF(CHARINDEX(',', @psCSString) - 1, -1),
                    LEN(@psCSString)))
  SET @psCSString = SUBSTRING(@psCSString,ISNULL(NULLIF(CHARINDEX(',', @psCSString), 0),
                               LEN(@psCSString)) + 1, LEN(@psCSString))
  INSERT INTO @otTemp VALUES (@sTemp)
 END

RETURN
END
Go

New Sproc

 SELECT *
 FROM
  TblJobs
 WHERE
  iCategoryID IN (SELECT * FROM UF_CSVToTable(@sCategoryID))
RSolberg
What he said. :) use a table valued function to parse the comma separated list.
Darren Clark
+1  A: 
SELECT * FROM Meeting WHERE Participants LIKE '%,12,%' OR Participants LIKE '12,%' OR Participants LIKE '%,12'

where 12 is the ID you are looking for....

Ugly, what a nasty model.

DancesWithBamboo
+3  A: 

Your table is not normalized. If you want to query for individual participants, they should be split into their own table, along the lines of:

Meeting
    MeetingId primary key
    Other stuff
Persons
    PersonId primary key
    Other stuff
Participants
    MeetingId foreign key Meeting(MeetingId)
    PersonId  foreign key Persons(PersonId)
    primary key MeetingId,PersonId

Otherwise, you have to resort to all sorts of trickery (what I call SQL gymnastics) to find out what you want. That trickery never scales well - your queries become slow very quickly as the table grows.

With a properly normalized database, the queries can remain fast well into the multi-millions of records (I work with DB2/z where we are used to truly huge tables).

There are valid reasons for sometimes reverting to second normal form (or even first) for performance but that should be a very hard thought out decision (and based on actual performance data). All databases should initially start of in 3NF.

paxdiablo
+3  A: 

You would not typically organise your SQL database in quite this way. What you are describing are two entities (Meeting & Participant) that have a one-to-many relationship. i.e. a meeting can have zero or more participants. To model this in SQL you would use three tables: a meeting table, a participant table and a MeetingParticipant table. The MeetingParticipant table holds the links between meetings & participants. So, you might have something like this (excuse any sql syntax errors)

create table Meeting
(
  MeetingID int,
  Name varchar(50),
  Location varchar(100)
)

create table Participant
(
  ParticipantID int,
  FirstName varchar(50),
  LastName varchar(50)
)

create table MeetingParticipant
(
  MeetingID int,
  ParticipantID int
)

To populate these tables you would first create some Participants:

insert into Participant(ParticipantID, FirstName, LastName) values(1, 'Tom', 'Jones')
insert into Participant(ParticipantID, FirstName, LastName) values(2, 'Dick', 'Smith')
insert into Participant(ParticipantID, FirstName, LastName) values(3, 'Harry', 'Windsor')

and create a Meeting or two insert into Meeting(MeetingID, Name, Location) values(10, 'SQL Training', 'Room 1') insert into Meeting(MeetingID, Name, Location) values(11, 'SQL Training', 'Room 2')

and now add some participants to the meetings

insert into MeetingParticipant(MeetingID, ParticipantID) values(10, 1)
insert into MeetingParticipant(MeetingID, ParticipantID) values(10, 2)
insert into MeetingParticipant(MeetingID, ParticipantID) values(11, 2)
insert into MeetingParticipant(MeetingID, ParticipantID) values(11, 3)

Now you can select all the meetings and the participants for each meeting with

select m.MeetingID, p.ParticipantID, m.Location, p.FirstName, p.LastName
from Meeting m 
  join MeetingParticipant mp on m.MeetingID=mp.MeetingID
  join Participant p on mp.ParticipantID=p.ParticipantID

the above should produce

MeetingID ParticipantID Location FirstName LastName
10        1             Room 1   Tom       Jones
10        2             Room 1   Dick      Smith
11        2             Room 2   Dick      Smith
11        3             Room 2   Harry     Windsor

If you want to find out all the meetings that "Dick Smith" is in you would write something like this

select m.MeetingID, m.Location
from Meeting m join MeetingParticipant mp on m.MeetingID=mp.ParticipantID
where
  mp.ParticipantID=2

and get

MeetingID Location
10        Room 1
11        Room 2

I have omitted important things like indexes, primary keys and missing attributes such as meeting dates, but it is clearer without all the goo.

Mike Thompson