November 18, 2004 at 9:45 am
Hello folks.
I've spent a few hours trying to suss this one out to no avail. There are lost of articals on how to do this with numeric values, but I cant find a single one related to strings.
Let me explain. I basically have some tables related to users and the groups they are members of.
I have a stored procedure which will gather details on these users based on criteria passed in.
I need to be able to collect a result set where the users are within a list of groups.
Heres the crunch. The group_id's are VARCHAR (damn) and use non numeric characters in all there glory. I have no control over the table structure, so couldn't change this.
So, My query looks something like this:
SELECT
User.fields_i_want
FROM User
WHERE
User_id IN (SELECT User_id FROM Group_member WHERE Group_id IN (@Search_param))
ORDER BY User_id ASC
No matter what I try, I just cant get my execute statement to work.
My execute looks something like this:
EXEC My_user_sp ''Group1', 'Group2', 'Group3''
As you can see, the single quotes mess this up. If I take the outside quotes out, each item in the list is treated as a seporate parameter. I've tried all sorts, and my head hurts.
Can anyone tell me if theres a way to do this?
Thanks for reading this,
Allan.
November 18, 2004 at 10:02 am
Try this ...
SELECT '''Group1'', ''Group2'', ''Group3'''
MK
November 18, 2004 at 10:09 am
Hi Allan,
Would it not be easier to build up the whole of the sql into a string and exec it?
This works perfectly, depends if you can build it......
DECLARE @sql varchar(8000),
@varNames varchar(8000)
SET @varNames = '''Roger''' + ', ' + '''Allan''' + ', ' + '''David'''
PRINT @varNames
SET @sql = 'SELECT NameFirst, NameMiddle, NameLast FROM tblNames WHERE NameFirst IN (' + @varNames + ')'
PRINT @sql
EXEC (@SQL)
Have fun
Steve
We need men who can dream of things that never were.
November 18, 2004 at 10:10 am
Make it a Dynamic stored procedure it should work...
CREATE Stored Procedure My_user_sp
@Search_Parm VARCHAR(100)
AS
DECLARE @sql VARCHAR(3000)
SET @sql = 'SELECT
User.fields_i_want
FROM User
WHERE
User_id IN (SELECT User_id FROM Group_member WHERE Group_id IN (' + @Search_param + '))
ORDER BY User_id ASC'
EXEC (@SQL)
EXEC My_user_sp '''Group1'', ''Group2'', ''Group3'''
MK
November 18, 2004 at 10:43 am
This is great, I'm making progress now. It works when I put the query into a variable first.
However, my problem is a little more complex. I Use embedded CURSOR's in my stored procedures. First I fetch the users, then the devices, the the timeframes for those devices.
The above dosn't seem to work for the query in my cursor, so I created a variable called @Qry, and tried to do the following:
DECLARE Qrecipient CURSOR FOR @Qry.
I get incorrect syntax. on the same line. Is there a way I can use the @Qry variable as my CURSOR?
I'm pretty sure this would solve my problem.
Thanks again,
Allan.
November 18, 2004 at 10:48 am
Can you post the query which you are trying to use.
November 18, 2004 at 10:58 am
Sure thing, OK the first query looks like this while filtering the users by groups ( the group id's are in the @Search_param):
SELECT
Recipient.Rcpt_id,
Recipient.Forename,
Recipient.Surname,
Recipient.Delete_ind,
Security_group.Security_group_desc,
Site.Site_name
FROM Recipient
INNER JOIN Site ON Site.Site_id=Recipient.Site_id
INNER JOIN Security_group ON Security_group.Security_group_id=Recipient.Security_group_id
WHERE
Recipient.Rcpt_id IN (SELECT Rcpt_id FROM Group_member WHERE Group_id IN (@Search_param))
ORDER BY Rcpt_id ASC
I call the sp like this
EXEC Rpt_gmd_rcpt 'grps', '''Group1'',''Group2'', ''etc''', 'id'
where the first parameter says use the above query, the second is the @Search_params, and the last is what I want the final result set to be ordered by.
As stated, the query returns good resuls when executed as a string in query analyser, however, as a CURSOR like above, it always returns nothing.
Allan.
November 19, 2004 at 4:26 am
If you're doing this in a stored proc you could try, instead of:
DECLARE Qrecipient CURSOR FOR @Qry.
the following:
DECLARE @Curs varchar(8000)
SET @Curs = 'DECLARE Qrecipient CURSOR FOR ' + @Qry
EXEC (@Curs)
HTH
Luigi
November 19, 2004 at 4:36 am
Some of the finest SQL heads around have contributed to this article:
http://www.sommarskog.se/arrays-in-sql.html
Although it's a quite long article, it might give you some ideas.
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org/blogs
My blog: http://www.insidesql.org/blogs/frankkalis/[/url]
November 19, 2004 at 4:48 am
i've been using stuff like this recently
patindex('%,' + @debt_type_cd + ',%', pa.DebtType) != 0
where @debt_type_cd is some value and pa.DebtType code is a comma delimited list like this
,something,somethingElse,morethings,
note the comma on the end
so you could use something like this
patindex('%,' + ColumnUsedForSearching + ',%', @CommaDelimitedParameterList) != 0
i read that it's one to avoid in the link fank posted, but i've never had any performance issues with this method maybe because i'm using variables and not columns...
hth
s
November 19, 2004 at 5:38 am
Everyone, you have been brill, and a credit to this site.
My problem is solved, which left me to get on with the task of finishing off the stored procedure.
So, here it is, in its entirity. Theres a lot of specific stuff related to the contents of the database, but some of it should help anyone else stumbling along this path:
CREATE PROCEDURE [dbo].[Rpt_gmd_rcpt]
@search_type VARCHAR(3),
@search_param VARCHAR(500),
@order_by VARCHAR(40)
AS
-- recipient info --
DECLARE @Rcpt_id NUMERIC(10)
DECLARE @Forename VARCHAR(40)
DECLARE @Surname VARCHAR(40)
DECLARE @Delete_ind NUMERIC(5)
DECLARE @Security_group_desc VARCHAR(40)
DECLARE @Site_name VARCHAR(40)
-- device info --
DECLARE @Device VARCHAR(80)
DECLARE @Device_id NUMERIC(9)
DECLARE @Device_type VARCHAR(3)
DECLARE @Device_desc VARCHAR(80)
DECLARE @Device_order NUMERIC(5)
DECLARE @Area_code VARCHAR(20)
DECLARE @Phone_number VARCHAR(20)
DECLARE @Email_address VARCHAR(80)
DECLARE @Attempt_limit NUMERIC(5)
DECLARE @Requeue_time NUMERIC(5)
DECLARE @Type_desc VARCHAR(80)
DECLARE @Use_desc VARCHAR(80)
-- timeframe info --
DECLARE @timeframe VARCHAR(80)
DECLARE @Device_timeframe_id NUMERIC(9)
DECLARE @Unavailable_ind NUMERIC(5)
DECLARE @Timeframe_start VARCHAR(8)
DECLARE @Timeframe_end VARCHAR(8)
DECLARE @Timeframe_desc VARCHAR(40)
-- the result table --
Declare @tbl table (
Rcpt_id NUMERIC(10),
Forename VARCHAR(40),
Surname VARCHAR(40),
Delete_ind NUMERIC(5),
Security_group_desc VARCHAR(40),
Site_name VARCHAR(40),
Device_id NUMERIC(9),
Device VARCHAR(80),
Device_timeframe_id NUMERIC(9),
timeframe VARCHAR(80)
)
DECLARE @q VARCHAR(8000)
SET @search_param=REPLACE(@Search_param,'|', '''')
IF @search_type='grp'
BEGIN
SET @q=' SELECT
Recipient.Rcpt_id,
Recipient.Forename,
Recipient.Surname,
Recipient.Delete_ind,
Security_group.Security_group_desc,
Site.Site_name
FROM Recipient
INNER JOIN Site ON Site.Site_id=Recipient.Site_id
INNER JOIN Security_group ON Security_group.Security_group_id=Recipient.Security_group_id
WHERE
Recipient.Rcpt_id IN (SELECT Rcpt_id FROM Group_member WHERE Group_id IN ('+@search_param+'))
ORDER BY Rcpt_id ASC'
END
ELSE
BEGIN
SET @q=' SELECT
Recipient.Rcpt_id,
Recipient.Forename,
Recipient.Surname,
Recipient.Delete_ind,
Security_group.Security_group_desc,
Site.Site_name
FROM Recipient
INNER JOIN Site ON Site.Site_id=Recipient.Site_id
INNER JOIN Security_group ON Security_group.Security_group_id=Recipient.Security_group_id
WHERE
CASE WHEN '+@search_type+'=''fn'' THEN
CONVERT(char(50),Recipient.Forename)
WHEN '+@search_type+'=''sn'' THEN
CONVERT(char(50),Recipient.Surname)
WHEN '+@search_type+'=''id'' THEN
CONVERT(char(50),Recipient.Rcpt_id)
END
LIKE ('+@search_param+') ORDER BY Rcpt_id ASC'
END
SET @q = 'DECLARE Qrecipient CURSOR READ_ONLY FOR ' + @q
EXEC (@q)
OPEN Qrecipient
FETCH NEXT FROM Qrecipient INTO @Rcpt_id, @Forename, @Surname, @Delete_ind, @Security_group_desc, @Site_name
WHILE @@FETCH_STATUS = 0
BEGIN
-- collect the device info --
DECLARE Qdevice CURSOR FOR
SELECT
Device.Device_id,
Device.Device_type,
Device.Device_desc,
Device.Device_order,
Device.Area_code,
Device.Phone_number,
Device.Email_address,
Device.Attempt_limit,
Device.Requeue_time,
Device_type.Device_desc AS Type_desc
FROM Device
INNER JOIN Device_type ON Device_type.Device_type=Device.Device_type
WHERE Rcpt_id=@Rcpt_id
ORDER BY Device_order ASC
OPEN Qdevice
FETCH NEXT FROM Qdevice INTO @Device_id,@Device_type, @Device_desc, @Device_order, @Area_code, @Phone_number, @Email_address, @Attempt_limit, @Requeue_time, @Type_desc
WHILE @@FETCH_STATUS = 0
BEGIN
-- create the device string --
SET @Use_desc=@Device_desc
IF @Device_desc IS NULL SET @Use_desc=@Type_desc
IF @Device_desc='' SET @Use_desc=@Type_desc
IF @Device_type = 'EML' SET @Device = @Use_desc+')'+@Email_address+'.';
IF @Device_type = 'PHN' SET @Device = @Use_desc+')'+@Area_code+@Phone_number+', with '+CAST(@Attempt_limit AS VARCHAR(9))+' Attempts requeued after '+CAST(@Requeue_time AS VARCHAR(9))+' minutes.';
IF @Device_type = 'TXT' SET @Device =@Use_desc+')'+@Phone_number+'.';
SET @Device = CAST(@Device_order AS VARCHAR(9))+': ('+ltrim(@Device);
-- collect the timeframe information for this device --
DECLARE Qtimeframe CURSOR FOR
SELECT
Device_timeframe.Device_timeframe_id,
Device_timeframe.Unavailable_ind,
Device_timeframe.Timeframe_start,
Device_timeframe.Timeframe_end,
Timeframe_type.Timeframe_desc
FROM Device_timeframe
INNER JOIN Timeframe_type ON Timeframe_type.Timeframe_type=Device_timeframe.timeframe_type
WHERE <A href="mailtoevice_id=@Device_id">Device_id=@Device_id
OPEN Qtimeframe
FETCH NEXT FROM Qtimeframe INTO @Device_timeframe_id, @Unavailable_ind, @Timeframe_start, @Timeframe_end, @Timeframe_desc
WHILE @@FETCH_STATUS = 0
BEGIN
-- create the timeframe string --
IF @Unavailable_ind=0 SET @timeframe='Available ';
IF @Unavailable_ind=1 SET @timeframe='Unavailable ';
IF @Timeframe_desc='Any Day' SET @timeframe=@timeframe+'any day' ELSE SET @timeframe=@timeframe+' '+@Timeframe_desc+'s';
SET @timeframe=@timeframe+' from '+@Timeframe_start+' to '+@Timeframe_end;
-- now we have all the details put them in the table --
INSERT INTO @tbl VALUES (
@Rcpt_id, @Forename, @Surname, @Delete_ind, @Security_group_desc, @Site_name,
@Device_id,@Device,
@Device_timeframe_id, @timeframe
 
FETCH NEXT FROM Qtimeframe INTO @Device_timeframe_id, @Unavailable_ind, @Timeframe_start, @Timeframe_end, @Timeframe_desc
END
CLOSE Qtimeframe
DEALLOCATE Qtimeframe
FETCH NEXT FROM Qdevice INTO @Device_id,@Device_type, @Device_desc, @Device_order, @Area_code, @Phone_number, @Email_address, @Attempt_limit, @Requeue_time, @Type_desc
END
CLOSE Qdevice
DEALLOCATE Qdevice
FETCH NEXT FROM Qrecipient INTO @Rcpt_id, @Forename, @Surname, @Delete_ind, @Security_group_desc, @Site_name
END
CLOSE Qrecipient
DEALLOCATE Qrecipient
select * from @tbl ORDER BY CASE
WHEN @order_by='fn' THEN CONVERT(char(50), Forename )
WHEN @order_by='sn' THEN CONVERT(char(50), Surname )
WHEN @order_by='id' THEN CONVERT(char(50), Rcpt_id)
END
ASC
Return
GO
Thanks to you all,
Allan.
November 19, 2004 at 7:54 am
Oh my god, I cannot believe how long of a solution you've made of this! Why didn't you first do a search on "Delimeted". I personally have posted a User Defined Function which you pass a String to and it returns a Table so that your queries are very fast.
Example:
Select * From Users Where FirstName IN(Select * From dbo.udf_GetDelimetedValues('Bob,Jim,Mary,Albert'))
Code:
CREATE FUNCTION
dbo.udf_GetDelimetedValues
(
@Values
VarChar(2000), @Delimeter VarChar(1) = ','
)
RETURNS
@Table Table(Value VarChar(256))
AS
BEGIN
-- Variables
Declare @Position SmallInt
Set @Position = 0
If (Right(@Values, 1) <> @Delimeter) Set @Values = @Values + @Delimeter
While (CharIndex(@Delimeter, @Values, @Position + 1) > 0)
BEGIN
Insert Into @Table
Values(
LTrim(RTrim(SubString(@Values, @Position, CharIndex(@Delimeter, @Values, @Position + 1) - @Position)))
)
Set @Position = CharIndex(@Delimeter, @Values, @Position + 1) + 1
END
RETURN
END
November 19, 2004 at 8:01 am
Yes, you really need to read the article I've reference. In the meantime what about?
SET NOCOUNT ON
SELECT
TOP 256 Number = IDENTITY(INT)
INTO
MyNumbers
FROM
Sysobjects S1
CROSS JOIN
Sysobjects S2
DECLARE @s-2 varchar(256)
SET @s-2 = 'Frank,,Foo,,,Bar,,'
SELECT
RIGHT(LEFT(@s,Number-1),CHARINDEX(',',REVERSE(LEFT(','+@s,Number-1))))
FROM
-- master..spt_values
MyNumbers
WHERE
-- Type = 'P'
--AND
Number BETWEEN 1 AND LEN(@s)
AND
SUBSTRING(@s,Number,1) = ',' AND SUBSTRING(@s,Number-1,1) <> ','
DROP TABLE MyNumbers
SET NOCOUNT OFF
Sometimes this numerical helper table works miracles.
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org/blogs
My blog: http://www.insidesql.org/blogs/frankkalis/[/url]
November 19, 2004 at 4:49 pm
At the risk of saying another "Why didn't you read..."
http://www.sqlservercentral.com/forums/shwmessage.aspx?forumid=8&messageid=143932#bm143942
Viewing 14 posts - 1 through 14 (of 14 total)
You must be logged in to reply to this topic. Login to reply
This website stores cookies on your computer.
These cookies are used to improve your website experience and provide more personalized services to you, both on this website and through other media.
To find out more about the cookies we use, see our Privacy Policy