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
 SQL Server 2000 Forums
 Transact-SQL (2000)
 Accessing each row of result set returned by EXEC

Author  Topic 

s2k
Starting Member

2 Posts

Posted - 2003-01-13 : 02:04:40
I have a dynamic SQL statement executed using EXEC. (It always returns a two-column result set. Each column is of type varchar.)

I want to go through each row in the result set. I can do it by first storing the EXEC result to a table or a temporary table. However, doing so is not acceptable for performance reasons (both involves writing to disk). I tried using a table variable but INSERT does not allow a table variable as source.

Is there a way to go through each row of a result set returned by EXEC without saving the result set to disk? Would it be possible to declare a cursor directly on the result of EXEC? How?


rihardh
Constraint Violating Yak Guru

307 Posts

Posted - 2003-01-13 : 02:24:50
Say what...?

Go to Top of Page

harshal_in
Aged Yak Warrior

633 Posts

Posted - 2003-01-13 : 02:32:48
quote:

I have a dynamic SQL statement executed using EXEC. (It always returns a two-column result set. Each column is of type varchar.)

I want to go through each row in the result set. I can do it by first storing the EXEC result to a table or a temporary table. However, doing so is not acceptable for performance reasons (both involves writing to disk). I tried using a table variable but INSERT does not allow a table variable as source.

Is there a way to go through each row of a result set returned by EXEC without saving the result set to disk? Would it be possible to declare a cursor directly on the result of EXEC? How?





I am not sure about this but CURSOR's seem the option for you if you want to go through each row of the result set but I think it is not possible to declare cursor directly on the result set of the exec.

Expect the UnExpected
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-01-13 : 07:30:41
I would make 100% sure it has to be dynamic SQL ... many times you can re-write the SQL w/o using dynamic SQL.

Post more detail of what you are trying to do and I'm sure we'll come up with a solution.

- Jeff
Go to Top of Page

s2k
Starting Member

2 Posts

Posted - 2003-01-13 : 20:32:55
To elaborate on my question, I have attached a simplified version of my stored procedure.

The first EXEC retrieves a subset of the whole list of persons. Filtering is done based on person status supplied during runtime.

The second EXEC is meant to obtain an exclusive lock on each person in the subset; that is, on each row of the result set returned by the first EXEC.

My problem is how to go through each row of the result set (returned by the first EXEC) in order to apply the second EXEC.

The stored procedure is meant to return a list of persons
* currently in a given status (1st EXEC), and
* locked successfully by the given process (2nd EXEC)

Thanks for any assistance.


CREATE Procedure ocm_persons_list
(
@process_id VarChar(10),
@lock_expiry_time Int,
@group_id Int,
@number_persons Int,
@status_id Int,
@retry_limit Int =999,
)
As
Begin
Declare @persons_table Varchar(50)
Select @persons_table = 'OCM_Persons_' + Cast(@group_id As VarChar)

-- Get filtered list of persons based on status.
-- This EXEC returns a result set. Each row has two varchar columns.

EXEC (' Declare @mystatus_id int
Set @mystatus_id = ' + @status_id + '

If @mystatus_id = 0
Begin
Select Top ' + @number_persons + '
ocm_person_id,
ocm_person_phone
From ' +
@persons_table + '
Where
ocm_status_id = ' + @status_id + '
End
Else if @mystatus_id = 4
Begin
Select Top ' + @number_persons + '
ocm_person_id,
ocm_person_phone
From ' +
@persons_table + '
Where
ocm_status_id = ' + @status_id + ' AND
ocm_calls_outbound_busy - 1 < ' + @retry_limit + '
End
Else if @mystatus_id = 3
<snip snip snip>
')

-- For each person (row in result set), lock it for some time for exclusive use
-- by a process. This step does another filtering on the list of persons.

EXEC (' Declare @proc_id VarChar(10),
@last_called_datetime Datetime,
@rows_changed Int
Select
@proc_id = ocm_process_id,
@last_called_datetime = ocm_last_called_datetime
From ' +
@persons_table + '
Where
ocm_person_id = ''' + @person_id + '''

-- No process has lock on person
If @proc_id Is Null
Begin
Update ' +
@persons_table + '
Set
ocm_process_id = ' + @process_id + ',
ocm_last_called_datetime = GETDATE()
Where
ocm_person_id = ''' + @person_id + '''
End

-- Another process has lock on person for quite some time now
Else If (DATEDIFF(ms, @last_called_datetime, GETDATE()) > ' + @lock_expiry_time + ')
Begin
Update ' +
@persons_table + '
Set
ocm_process_id = ' + @process_id + ',
ocm_last_called_datetime = GETDATE()
Where
ocm_person_id = ''' + @person_id + '''
End

-- Given process has lock on person
Else If @proc_id = ' + @process_id + '
Begin
<snip snip>
End

-- Another process has lock obtained just recently
Else
Begin
<snip snip>
End')
End
GO


Go to Top of Page

Page47
Master Smack Fu Yak Hacker

2878 Posts

Posted - 2003-01-14 : 07:35:30
I think you should start from scratch and explain the business need or requirement you are trying to fulfill. You should provide some ddl and sample data along with an expected result.

Row-by-row iteration and dynamic SQL are each red flags. SQL is a set based language and should be approached as such.

By the way, what does your organization define as "acceptable performance" and how far off was your temp table design?

Jay White
{0}
Go to Top of Page

nr
SQLTeam MVY

12543 Posts

Posted - 2003-01-14 : 07:55:12
What if something gets a lock between these two statements?
What if the process that has the lock crashes without releasing it?
You will then have to wait for the @lock_expiry_time.
If you have a client server system it is easy to tell whether or not the locking process still exists.

Why not do the update of @persons_table as a set based operation for all the locks that are available then you only have to deal with the ones that aren't.
And why not also get the locks in the remainder as a set based operation?
Just join to the temp table.
This means you don't have to do any row by row operations and should be lots quicker.

Must say I would be dubious about what you are trying to do though - trying to lock many records like this.


==========================================
Cursors are useful if you don't know sql.
DTS can be used in a similar way.
Beer is not cold and it isn't fizzy.
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-01-14 : 10:09:24
quote:

Declare @persons_table Varchar(50)
Select @persons_table = 'OCM_Persons_' + Cast(@group_id As VarChar)

EXEC (' Declare @mystatus_id int
Set @mystatus_id = ' + @status_id + '

If @mystatus_id = 0
Begin
Select Top ' + @number_persons + '
ocm_person_id,
ocm_person_phone
From ' +
@persons_table + '
Where
ocm_status_id = ' + @status_id + '
End
Else if @mystatus_id = 4
Begin
Select Top ' + @number_persons + '
ocm_person_id,
ocm_person_phone
From ' +
@persons_table + '
Where
ocm_status_id = ' + @status_id + ' AND
ocm_calls_outbound_busy - 1 < ' + @retry_limit + '
End
Else if @mystatus_id = 3



Why do you have different groups of people in different tables? I would really recommend looking into this because if the data is basically the same, it should be in the same table, with an added "Group" field to distinguish between the groups a person is in.

Also, you can use SET ROWCOUNT instead of a dynamic TOP statement.

If you MUST keep everyone in different tables, here is a way to do this w/o dynamic SQL (if you don't have too many tables to list, that is):

SELECT * FROM persons_group_10 WHERE @Group = '10'
UNION ALL
SELECT * FROM persons_group_20 WHERE @Group = '20'
UNION ALL
..etc....

Combine that with a SET ROWCOUNT and you no longer need dynamic SQL. But I really recommend putting all "persons" in the same table.

I really still have no idea what you are trying to do with this stored proc, but I suspect your main problem is your database structure. Then, look into using JOINS instead of cursors and dealing with sets of records at a time, instead of 1 by 1.


- Jeff

Edited by - jsmith8858 on 01/14/2003 10:09:43
Go to Top of Page
   

- Advertisement -