I have created an item on the Degree table and I want to duplicate that record for 19 other Colleges. I have a really simple cursor, but every time I run it it totally crashes SQL Server Management Studio. Is there a way to rewrite this query (or another query entirely which performs the same INSERT INTO) so that it does not crash (and actually executes)?
DECLARE #Colleges VARCHAR(200)
DECLARE DUPLICATE_DEGREE CURSOR FOR
SELECT CollegeID FROM Colleges WHERE CollegeName <> 'Main Office'
OPEN DUPLICATE_DEGREE
FETCH NEXT FROM DUPLICATE_DEGREE INTO #Colleges
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO Degree
(
DegreeName
, CollegeID
)
SELECT
DegreeName
, #Colleges
FROM Degrees
WHERE DegreeID = 123
END
CLOSE DUPLICATE_DEGREE
DEALLOCATE DUPLICATE_DEGREE
Your script is getting stuck in an infinite loop because you're never advancing the cursor and therefore the value of ##FETCH_STATUS never changes resulting in you adding the same record for the same college ad nauseum. Add FETCH NEXT FROM DUPLICATE_DEGREE INTO #Colleges after the INSERT.
Jake - you don't need a cursor, try this:
DECLARE #DegreeName varchar (256)
SET #DegreeName = SELECT DISTINCT DegreeName from Degrees WHERE DegreeID = 123
INSERT INTO Degree (DegreeName, CollegeID)
SELECT #DegreeName, CollegeID
FROM Colleges WHERE CollegeName <> 'Main Office'
Related
For a homework assignment, I'm trying to build a trigger that allows for multiple inserts/updates/deletes by utilizing a cursor. We have to use a cursor in order to practice the syntax. We know that there are very few practical scenarios for cursors in a production environment.
Here's what I'm trying to accomplish:
For each row inserted into the TAL_ORDER_LINE table, update the ON_HAND value in the TAL_ITEM table by subtracting the NUM_ORDERED value from the stored ON_HAND value.
Table Structure:
Current Query:
ALTER TRIGGER update_on_hand
ON TAL_ORDER_LINE
AFTER INSERT AS
DECLARE #vItemNum as char
DECLARE #vNumOrdered as int
DECLARE new_order CURSOR FOR
SELECT ITEM_NUM, NUM_ORDERED
FROM inserted
OPEN new_order;
FETCH NEXT FROM new_order INTO #vItemNum, #vNumOrdered;
WHILE ##FETCH_STATUS=0
BEGIN
UPDATE TAL_ITEM
SET ON_HAND = ON_HAND - #vNumOrdered
WHERE ITEM_NUM = #vItemNum
FETCH NEXT FROM new_order INTO #vItemNum, #vNumOrdered;
END
CLOSE new_order
DEALLOCATE new_order
My Insert Query:
INSERT INTO TAL_ORDER_LINE (ORDER_NUM, ITEM_NUM, NUM_ORDERED, QUOTED_PRICE)
VALUES (51626, 'KL78', 10, 10.95), (51626, 'DR67', 10, 29.95)
It runs successfully, but does not affect the ON_HAND value. I think the biggest problem is that I'm struggling to understand cursor syntax, especially the INTO clause in the FETCH statement and how data from the 'inserted' table is passed into the cursor. What do I need to know to get this to work? Thanks in advance!
Your problem is likely due to this:
DECLARE #vItemNum as char
it is HIGHLY unlikely that the ItemNum column is a single character. For future reference, you should always verify that you variable definitions are consistent with the values you expect to store in them. And as has been hinted - you will get better answers by posting a complete script rather than a picture.
Big question,how you gonna debug ?
Is On_Hand col NULL , then do this isnull(on_Hand,0)
DECLARE #vItemNum as char
DECLARE #vNumOrdered as int
DECLARE new_order CURSOR FOR
SELECT ITEM_NUM, NUM_ORDERED
FROM TAL_ORDER_LINE
OPEN new_order;
FETCH NEXT FROM new_order INTO #vItemNum, #vNumOrdered;
WHILE ##FETCH_STATUS=0
BEGIN
--UPDATE TAL_ITEM
--SET ON_HAND = ON_HAND - #vNumOrdered
--WHERE ITEM_NUM = #vItemNum
print #vItemNum
print vNumOrdered
FETCH NEXT FROM new_order INTO #vItemNum, #vNumOrdered;
END
CLOSE new_order
DEALLOCATE new_order
Try this :
ALTER TRIGGER update_on_hand ON TAL_ORDER_LINE
FOR INSERT AS
BEGIN
UPDATE TI
SET TI.ON_HAND = TI.ON_HAND - I.NUM_ORDERED
TAL_ITEM TI INNER JOIN
INSERTED I ON I.ITEM_NUM = TI.ITEM_NUM
END
Changed Trigger to FOR INSERT Trigger
Removed Cursor
Note: NOT Tested. ( If you post the sql scripts for create table + sample inserts I can give it a try )
I have a table with 700 rows. What I want to do is, to execute `select * from table_name' query on it and whatever result I will get want to store it in a variable and after that is done, want to traverse through each record for processing purpose? How do I achieve it? Any help??
Thanks in adv,
-saurabh
you want something which is called cursors
Cursors
You use a cursor to fetch rows returned by a query. You retrieve the rows into the cursor using a query and then fetch the rows one at a time from the cursor.
Steps
Declare variables to store the column values for a row.
Declare the cursor, which contains a query.
Open the cursor.
Fetch the rows from the cursor one at a time and store the column values in the variables declared in Step 1. You would then do something with those variables; such as display them on the screen, use them in a calculation, and so on.
Close the cursor.
hopefully this might help you cursor
here is an example I use to start with
USE pubs
GO
-- Declare the variables to store the values returned by FETCH.
DECLARE #au_lname varchar(40), #au_fname varchar(20)
DECLARE authors_cursor CURSOR FOR
SELECT au_lname, au_fname FROM authors
--WHERE au_lname LIKE 'B%'
ORDER BY au_lname, au_fname
OPEN authors_cursor
-- Perform the first fetch and store the values in variables.
-- Note: The variables are in the same order as the columns
-- in the SELECT statement.
FETCH NEXT FROM authors_cursor
INTO #au_lname, #au_fname
-- Check ##FETCH_STATUS to see if there are any more rows to fetch.
WHILE ##FETCH_STATUS = 0
BEGIN
-- Concatenate and display the current values in the variables.
PRINT #au_fname
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM authors_cursor
INTO #au_lname, #au_fname
END
CLOSE authors_cursor
DEALLOCATE authors_cursor
GO
I need some tip on tuning some TSQL to execute faster, it's taking way too long although it works. This may be because I'm fetching a key from another table before I can do the insert, any ideas anyone?
DECLARE db_cursorReads CURSOR FOR SELECT
[MeterId]
,[MeterRead]
FROM MdsReadsImports;
declare #PremiseMeterId int;
declare #MeterId nvarchar(24);
declare #MeterRead int;
OPEN db_cursorReads;
FETCH NEXT FROM db_cursorReads INTO
#MeterId
,#MeterRead;
WHILE ##FETCH_STATUS = 0
BEGIN
set #PremiseMeterId = (select top 1 PremiseMeterId from PremiseMeters where MeterId = #MeterId)
insert into PremiseMeterReads (MeterRead,PremiseMeterId)
values (#MeterRead, #MPremiseMeterId)
FETCH NEXT FROM db_cursorReads INTO
#MeterId
,#MeterRead;
END;
CLOSE db_cursorReads;
DEALLOCATE db_cursorReads;
I see you are retrieving PremiseMeterId but not using it in the script you posted. Perhaps you can ditch the cursor and perform a single set-based query:
INSERT INTO PremiseMeterReads (MeterRead,MeterId)
SELECT
[MeterRead]
,[MeterId]
FROM MdsReadsImports;
First, I note that you are setting but not using #PremiseMeterID.
Second, you seem to be doing this:
insert into PremiseMeterReads (MeterRead, MeterId)
select MeterRead, MeterId
from MdsReadsImports;
A set based operation should be much faster than using a cursor.
I have a piece of script using cursor to sequence rows in a table. For example, the table looks like this,
SSN, Kid_SSN, Kid_DOB, Seq# to list every person with 1 or more kids. I want to update Seq# to label each kid as 1,2,3... based on Date Of Birth.
I used cursor for update to get it done successfully in SQL server 2008. My current trouble is that this same script wouldn't run as expected in sql server 2012. The problem is in SQL 2012 cursor fetch NEXT more than 1 row at a time. So question is where can I set the cursor fetch size? I searched around but came up no good answer.
Anyone here can shed some light? thanks.
Scrip looks like this:
DECLARE #SocialSecurity varchar(9), #PersonID int, #Dep_SSN varchar(9)
DECLARE #LastName varchar(20), #FirstName varchar(20), #BirthDate datetime,
#Number int
DECLARE #ssn varchar(9) = '000000000'
DECLARE #Mem int = 1
DECLARE cur cursor
FOR SELECT * FROM kids
FOR UPDATE OF Number;
OPEN cur;
FETCH NEXT FROM cur INTO #SocialSecurity, #PersonID, #Dep_SSN, #LastName, #FirstName,
#BirthDate, #Number;
WHILE ##FETCH_STATUS = 0
BEGIN
IF #SocialSecurity = #ssn
BEGIN
UPDATE kids
SET Number = #Mem+1
WHERE CURRENT OF cur
SET #Mem = #Mem+1
END;
ELSE
BEGIN
SET #ssn = #SocialSecurity
SET #Mem = 1
END;
FETCH NEXT FROM cur INTO #SocialSecurity, #PersonID, #Dep_SSN, #LastName, #FirstName,
#BirthDate, #Number;
END;
CLOSE cur;
DEALLOCATE cur;
More info on this problem.
kids is a temp table generated by 'SELECT .. INTO' and a simplified set looks like this
SSN Kid_SSN DOB Seq#
123123123 987987987 1/1/2000 1
123123123 987987988 1/1/2003 1
123123125 890890890 2/3/2002 1
So all seq# are initiated to 1. After going through the script above, I expect table kids to
look like this
SSN Kid_SSN DOB Seq#
123123123 987987987 1/1/2000 1
123123123 987987988 1/1/2003 2
123123125 890890890 2/3/2002 1
The script ran perfectly to achieve this on server 2008 R2, but not on server 2012. Furthermore, I found that it only updated row 88, 176 and so on, if applicable. That is why I think cursor fetch 88 rows at a time. But on server 2008 it apparently fetch 1 row at a time as I expected. Hope this will explain the problem I have.
I want to force cursor fetching 1 row at a time to make it work on server 2012, though it's not efficient. Or, how to do sequencing without using cursor? Thanks.
Would it work to replace the entire script with a rank over function?
Something like
select *, rank() over (partition by SSN, Kid_DOB order by Kid_SSN) as SeqNum
from kids
I think this should work and if not you can tweak the partition and order by to make it work.
Your script requires that the cursor on kids groups records by the same SSN. But there is no ORDER BY to enforce this. Thus the records are being returned in some random order which messes up the #Mem counter.
It's not an issue with SQL 2012 vs. 2008. I believe you simply lucked out with SQL 2008 and the records were already ordered the way you wanted them, or SQL 2008 has a different behavior for selecting unordered results, or you defined the pk and indexes differently.
I have a stored procedure, which contains a simple select statement:
ALTER PROCEDURE [dbo].[TransferAuditRecords]
As
SET NOCOUNT ON
SET XACT_ABORT ON
Declare #UserCode As varchar(50)
DECLARE AuditCursor CURSOR FOR
select top 1 UserCode from [AuditDatabaseServer].AuditDatabase.dbo.dbaudit where auditdate >= '2012-09-04'
Open AuditCursor
FETCH NEXT FROM AuditCursor INTO #UserCode
WHILE ##FETCH_STATUS = 0
BEGIN
Print #Usercode
FETCH NEXT FROM AuditCursor INTO #UserCode
END
Close AuditCursor
Deallocate AuditCursor
There are a few lines of code missing, which I excluded as they are irrelevant to the question.
If I execute the SQL statement without the stored procedure i.e. in SQL Studio Manager 2005 then I get a different output than if I run the stored procedure i.e. the top reference returned is different. Why are the outputs different?
I am fairly sure that the reason for this is because SQL Server uses a different execution plan for compiled code is comparison to code being run in SQL Studio Manager. I wanted to check though.
Use an ORDER BY clause to predictably indicate which row is selected.
e.g. select top 1... order by auditdate
Unrelated:: is the use of a cursor required by part of the code you removed? I guess so, otherwise a simpler "select top 1 #UserCode = UserCode from..." would be enough.