If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

 
Go Back  dBforums > Database Server Software > Microsoft SQL Server > Move through rows in table

Reply
 
LinkBack Thread Tools Display Modes
  #1 (permalink)  
Old 01-06-09, 09:48
KevCB226 KevCB226 is offline
Registered User
 
Join Date: Sep 2005
Posts: 232
Move through rows in query

Afternoon peeps,

I need some help on a stored procedure I'm creating.

Here are the facts:

At work we have a web based CRM and amongst various details stored in the database (SQL Server 2000), it also stores actions created by users.

What I'm trying to do is setup a stored procedure that checks these actions.
If they are not completed and overdue or not completed and are near the due date, I want to send an e-mail to the user to remind them or bring to their attention that it is overdue.

So I set about setting up SQL Mail and started creating the stored procedure.

Here is my problem:

So far I've got my stored procedure working, but it only gets one row of data from the query.

I fire off an e-mail with the details of the users action, but it only returns the details in the last row.

How do I select the details from each row in the query, rather than just one row?

Here is my procedure so far:

Code:
ALTER PROCEDURE [dbo].[sp_CRMActions] 
    -- Add the parameters for the stored procedure here
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- SET Variables
    DECLARE @email nvarchar(50), @notes nvarchar(255), @subject nvarchar(75), @msg nvarchar(255), @rows int, @k int

    IF (SELECT dbo.tblActions.acti_due_datetime    FROM dbo.tblActions WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL)) < GETDATE()
    BEGIN

    SET @rows = @@ROWCOUNT
    SET @k = 1

    WHILE @k <= @rows
    BEGIN
        SELECT @email = dbo.tblUsers.user_email
        FROM dbo.tblActions INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
        WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime < GETDATE())

        SELECT @notes = dbo.tblActions.acti_notes
        FROM dbo.tblActions INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
        WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime < GETDATE())

        SELECT @subject = dbo.tblActions.acti_subject
        FROM dbo.tblActions INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
        WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime < GETDATE())

        -- Insert statements for procedure here
        SELECT dbo.tblActions.acti_user_id, dbo.tblActions.acti_subject, dbo.tblActions.acti_priority, dbo.tblActions.acti_notes, dbo.tblUsers.user_email
        FROM dbo.tblActions INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
        WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime < GETDATE())

        SET @msg = 'An action you created in the CRM is overdue.' + CHAR(13) + CHAR(10) +
                   'Please go back and sheck the status of your action. Here is a description of the action:' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                    @subject + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                    @notes + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                    'Regards,' + CHAR(13) + CHAR(10) +
                    'The MIS Team'

        -- Send the e-mail
        EXEC master.dbo.xp_sendmail
        @recipients = @email,
        @subject = 'You have an overdue action in the CRM which needs attention!',
        @message = @msg;

    SET @k = @k + 1
    END

    END
    ELSE

        SELECT dbo.tblActions.acti_due_datetime
        FROM dbo.tblActions
        WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime > GETDATE())

        SET @rows = @@rOWCOUNT
        SET @k = 1

        WHILE @k <= @rows
        BEGIN
            SELECT @email = dbo.tblUsers.user_email
            FROM dbo.tblActions INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
            WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime > GETDATE())

            SELECT @notes = dbo.tblActions.acti_notes
            FROM dbo.tblActions INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
            WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime > GETDATE())

            SELECT @subject = dbo.tblActions.acti_subject
            FROM dbo.tblActions INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
            WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime > GETDATE())

            -- Insert statements for procedure here
            SELECT dbo.tblActions.acti_user_id, dbo.tblActions.acti_subject, dbo.tblActions.acti_priority, dbo.tblActions.acti_notes, dbo.tblUsers.user_email
            FROM dbo.tblActions INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
            WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime > GETDATE())

            SET @msg = 'An action you created in the CRM is almost due.' + CHAR(13) + CHAR(10) +
                       'Please go back and sheck the status of your action. Here is a description of the action:' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        @subject + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        @notes + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        'Regards,' + CHAR(13) + CHAR(10) +
                        'The MIS Team'

            -- Send the e-mail
            EXEC master.dbo.xp_sendmail
            @recipients = @email,
            @subject = 'You have an upcoming action in the CRM which needs attention!',
            @message = @msg;

        SET @k = @k + 1
        END

END
__________________
<- Hides behind a rock.

Last edited by KevCB226; 01-06-09 at 10:29. Reason: Was table, now query
Reply With Quote
  #2 (permalink)  
Old 01-06-09, 10:30
blindman blindman is offline
World Class Flame Warrior
 
Join Date: Jun 2003
Location: Ohio
Posts: 10,830
Are you sending off one e-mail per action, or one e-mail per user?
__________________
If it's not practically useful, then it's practically useless.

blindman
www.chess.com: "sqlblindman"
Reply With Quote
  #3 (permalink)  
Old 01-06-09, 10:32
KevCB226 KevCB226 is offline
Registered User
 
Join Date: Sep 2005
Posts: 232
It's one e-mail per action.

Just realised I had put table instead of query, so I've corrected the post
__________________
<- Hides behind a rock.
Reply With Quote
  #4 (permalink)  
Old 01-06-09, 10:37
tomh53 tomh53 is offline
9th inning DBA
 
Join Date: Jan 2004
Location: In a large office with bad lighting
Posts: 1,036
What is the value of @@ROWCOUNT after the IF (SELECT ... )?

I suspect it is 1, so you would only get 1 row before your @k is > @rows thereby ending your loop.

Try:
Code:
 
select @rows = count(*) 
from dbo.tblActions   
WHERE dbo.tblActions.acti_complete = 0 
   AND COALESCE(dbo.tblActions.acti_due_datetime,getdate()) < GETDATE()
__________________

-- This is all just a Figment of my Imagination --
Reply With Quote
  #5 (permalink)  
Old 01-06-09, 10:43
blindman blindman is offline
World Class Flame Warrior
 
Join Date: Jun 2003
Location: Ohio
Posts: 10,830
Set up a cursor that selects the primary key of all the actions that need to be e-mailed. Then loop through the cursor, storing the primary key value in a variable and using it to filter and identify the rest of the information that needs to be included in the e-mail.
__________________
If it's not practically useful, then it's practically useless.

blindman
www.chess.com: "sqlblindman"
Reply With Quote
  #6 (permalink)  
Old 01-06-09, 11:26
KevCB226 KevCB226 is offline
Registered User
 
Join Date: Sep 2005
Posts: 232
I tried adding a cursor to the query before, but it told me I couldn't do this due to the local variables.

This is what I did:

Code:
DECLARE overdue_cursor CURSOR
FOR SELECT @email = dbo.tblUsers.user_email, @notes = dbo.tblActions.acti_notes, @subject = dbo.tblActions.acti_subjectFROM dbo.tblActions
INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime > GETDATE())

OPEN overdue_cursor
FETCH NEXT FROM overdue_cursor
__________________
<- Hides behind a rock.
Reply With Quote
  #7 (permalink)  
Old 01-06-09, 11:43
tomh53 tomh53 is offline
9th inning DBA
 
Join Date: Jan 2004
Location: In a large office with bad lighting
Posts: 1,036
That is not a valid cursor. The cursor declaration select the columns. The fetch assigns them to the variables.

Code:
DECLARE overdue_cursor CURSOR FOR 
SELECT dbo.tblUsers.user_email, dbo.tblActions.acti_notes, dbo.tblActions.acti_subject
FROM dbo.tblActions
INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime > GETDATE())
 
OPEN overdue_cursor
FETCH NEXT FROM overdue_cursor into @email, @notes, @subject
WHILE @@FETCH_STATUS = 0
BEGIN
   <processing steps>
   FETCH NEXT FROM overdue_cursor into @email, @notes, @subject
END
 
CLOSE CURSOR overdue_cursor
 
DEALLOCATE overdue_cursor
__________________

-- This is all just a Figment of my Imagination --
Reply With Quote
  #8 (permalink)  
Old 01-06-09, 12:00
KevCB226 KevCB226 is offline
Registered User
 
Join Date: Sep 2005
Posts: 232
Thanks Tom, I'll give it a go tomorrow
__________________
<- Hides behind a rock.
Reply With Quote
  #9 (permalink)  
Old 01-07-09, 05:35
KevCB226 KevCB226 is offline
Registered User
 
Join Date: Sep 2005
Posts: 232
Thanks guys,

I've managed to get one of the the cursors working.

The second cursor works great, but the first cursor doesn't get run at all.
I think it's the IF...ELSE statement causing the problem, as when I run the procedure I get this error:

Quote:
Msg 512, Level 16, State 1, Procedure sp_CRMActions2, Line 18
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The IF...ELSE statement was put in to determine whether the action is overdue or not.

Code:
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- SET Variables
    DECLARE @email nvarchar(50), @notes nvarchar(255), @subject nvarchar(75), @msg nvarchar(255)

    IF (SELECT dbo.tblActions.acti_due_datetime FROM dbo.tblActions WHERE EXISTS 
        (SELECT dbo.tblActions.acti_id FROM dbo.tblActions) AND (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL)) < GETDATE()
    BEGIN

        -- Set cursor to run through rows in query
        DECLARE overdue_cursor CURSOR FOR
            SELECT dbo.tblUsers.user_email, dbo.tblActions.acti_notes, dbo.tblActions.acti_subject
            FROM dbo.tblActions INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
            WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime < GETDATE())

        OPEN overdue_cursor
        -- Get the values from the query and store them in the variables
        FETCH NEXT FROM overdue_cursor INTO @email, @notes, @subject
        WHILE @@FETCH_STATUS = 0
        BEGIN
            -- Set the e-mail message
            SET @msg = 'An action you created in the CRM is overdue.' + CHAR(13) + CHAR(10) +
                       'Please go back and sheck the status of your action. Here is a description of the action:' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        @subject + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        @notes + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        'Regards,' + CHAR(13) + CHAR(10) +
                        'The MIS Team'

            -- Send the e-mail
            EXEC master.dbo.xp_sendmail
            @recipients = @email,
            @subject = 'You have an overdue action in the CRM which needs attention!',
            @message = @msg;
            -- Get values from next row
            FETCH NEXT FROM overdue_cursor INTO @email, @notes, @subject
        END

        CLOSE overdue_cursor

        DEALLOCATE overdue_cursor

    END
    ELSE

        -- Set cursor to run through rows in query
        DECLARE upcoming_cursor CURSOR FOR
            SELECT dbo.tblUsers.user_email, dbo.tblActions.acti_notes, dbo.tblActions.acti_subject
            FROM dbo.tblActions INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
            WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime > GETDATE())

        OPEN upcoming_cursor
        -- Get the values from the query and store them in the variables
        FETCH NEXT FROM upcoming_cursor INTO @email, @notes, @subject
        WHILE @@FETCH_STATUS = 0
        BEGIN
            -- Set the e-mail message
            SET @msg = 'An action you created in the CRM is almost due.' + CHAR(13) + CHAR(10) +
                       'Please go back and sheck the status of your action. Here is a description of the action:' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        @subject + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        @notes + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        'Regards,' + CHAR(13) + CHAR(10) +
                        'The MIS Team'

            -- Send the e-mail
            EXEC master.dbo.xp_sendmail
            @recipients = @email,
            @subject = 'You have an upcoming action in the CRM which needs attention!',
            @message = @msg;
            -- Get values from next row
            FETCH NEXT FROM upcoming_cursor INTO @email, @notes, @subject
        END

        CLOSE upcoming_cursor

        DEALLOCATE upcoming_cursor

END
__________________
<- Hides behind a rock.

Last edited by KevCB226; 01-07-09 at 06:53.
Reply With Quote
  #10 (permalink)  
Old 01-07-09, 05:45
pootle flump pootle flump is offline
King of Understatement
 
Join Date: Feb 2004
Location: One Flump in One Place
Posts: 14,148
Code:
   IF EXISTS (SELECT NULL FROM dbo.tblActions WHERE dbo.tblActions.acti_complete = 0 AND dbo.tblActions.acti_due_datetime < GETDATE())
    BEGIN
__________________
Testimonial:
Quote:
pootle flump
ur codings are working excelent.
Reply With Quote
  #11 (permalink)  
Old 01-07-09, 07:10
KevCB226 KevCB226 is offline
Registered User
 
Join Date: Sep 2005
Posts: 232
It's soo close and almost there, but still not quite right.

The select you posted (poots) has stopped that error, and it now works, but the else part of the statement doesn't work.

The following errors are returned:

Quote:
Msg 16916, Level 16, State 1, Procedure sp_CRMActions2, Line 65
A cursor with the name 'upcoming_cursor' does not exist.
Msg 16916, Level 16, State 1, Procedure sp_CRMActions2, Line 67
A cursor with the name 'upcoming_cursor' does not exist.
Msg 16916, Level 16, State 1, Procedure sp_CRMActions2, Line 87
A cursor with the name 'upcoming_cursor' does not exist.
Msg 16916, Level 16, State 1, Procedure sp_CRMActions2, Line 89
A cursor with the name 'upcoming_cursor' does not exist.
So I then copied the IF EXISTS and swapped the date filter around, which does get rid of the errors, but then I don't get any e-mails via the sendmail for actions that will be due in the future.
I only get e-mailed about actions that are overdue.

Code:
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- SET Variables
    DECLARE @email nvarchar(50), @notes nvarchar(555), @subject nvarchar(75), @msg nvarchar(755)

    IF EXISTS (SELECT NULL FROM dbo.tblActions WHERE dbo.tblActions.acti_complete = 0 AND dbo.tblActions.acti_due_datetime < GETDATE())
    BEGIN

        -- Set cursor to run through rows in query
        DECLARE overdue_cursor CURSOR FOR
            SELECT dbo.tblUsers.user_email, dbo.tblActions.acti_notes, dbo.tblActions.acti_subject
            FROM dbo.tblActions INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
            WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime < GETDATE())

        OPEN overdue_cursor
        -- Get the values from the query and store them in the variables
        FETCH NEXT FROM overdue_cursor INTO @email, @notes, @subject
        WHILE @@FETCH_STATUS = 0
        BEGIN
            -- Set the e-mail message
            SET @msg = 'An action you created in the CRM is overdue.' + CHAR(13) + CHAR(10) +
                       'Please go back and sheck the status of your action. Here is a description of the action:' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        @subject + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        @notes + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        'Regards,' + CHAR(13) + CHAR(10) +
                        'The MIS Team'

            -- Send the e-mail
            EXEC master.dbo.xp_sendmail
            @recipients = @email,
            @subject = 'You have an overdue action in the CRM which needs attention!',
            @message = @msg;
            -- Get values from next row
            FETCH NEXT FROM overdue_cursor INTO @email, @notes, @subject
        END

        CLOSE overdue_cursor

        DEALLOCATE overdue_cursor

    END
    ELSE
        IF EXISTS (SELECT NULL FROM dbo.tblActions WHERE dbo.tblActions.acti_complete = 0 AND dbo.tblActions.acti_due_datetime > GETDATE())
    BEGIN
        -- Set cursor to run through rows in query
        DECLARE upcoming_cursor CURSOR FOR
            SELECT dbo.tblUsers.user_email, dbo.tblActions.acti_notes, dbo.tblActions.acti_subject
            FROM dbo.tblActions INNER JOIN dbo.tblUsers ON dbo.tblActions.acti_user_id = dbo.tblUsers.user_id
            WHERE (dbo.tblActions.acti_complete = 0) AND (dbo.tblActions.acti_due_datetime IS NOT NULL) AND (dbo.tblActions.acti_due_datetime > GETDATE())

        OPEN upcoming_cursor
        -- Get the values from the query and store them in the variables
        FETCH NEXT FROM upcoming_cursor INTO @email, @notes, @subject
        WHILE @@FETCH_STATUS = 0
        BEGIN
            -- Set the e-mail message
            SET @msg = 'An action you created in the CRM is almost due.' + CHAR(13) + CHAR(10) +
                       'Please go back and sheck the status of your action. Here is a description of the action:' + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        @subject + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        @notes + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) +
                        'Regards,' + CHAR(13) + CHAR(10) +
                        'The MIS Team'

            -- Send the e-mail
            EXEC master.dbo.xp_sendmail
            @recipients = @email,
            @subject = 'You have an upcoming action in the CRM which needs attention!',
            @message = @msg;
            -- Get values from next row
            FETCH NEXT FROM upcoming_cursor INTO @email, @notes, @subject
        END

        CLOSE upcoming_cursor

        DEALLOCATE upcoming_cursor
    END
END
__________________
<- Hides behind a rock.
Reply With Quote
  #12 (permalink)  
Old 01-07-09, 07:24
pootle flump pootle flump is offline
King of Understatement
 
Join Date: Feb 2004
Location: One Flump in One Place
Posts: 14,148
Why not open one cursor and test the date?
__________________
Testimonial:
Quote:
pootle flump
ur codings are working excelent.
Reply With Quote
  #13 (permalink)  
Old 01-07-09, 10:17
KevCB226 KevCB226 is offline
Registered User
 
Join Date: Sep 2005
Posts: 232
Wahey, it works!!.
Thanks, I should of used that structure in the first place methinks
__________________
<- Hides behind a rock.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On