I tried creating a store procedure for MS SQL
CREATE PROCEDURE YEARENDPROCESSING
AS
DECLARE #VAR AS VARCHAR(9)
DECLARE ACURSOR CURSOR FOR
SELECT COLUMN FROM TABLEA
OPEN ACURSOR
FETCH NEXT FROM ACURSOR INTO #VAR
while ##FETCH_STATUS = 0
BEGIN
INSERT INTO TABLEB SELECT * FROM TABLEC WHERE TABLEC.COLUMNC = #VAR
FETCH NEXT FROM ACURSOR INTO #VAR
END
CLOSE ACURSOR
DEALLOCATE ACURSOR
Assuming TableC column and TableB have identical columns
I get the result saying X rows affected
But in actual table I see nothing.
I have a new Finding
CREATE PROCEDURE YEARENDPROCESSING
AS
DECLARE #VAR AS VARCHAR(9)
DECLARE ACURSOR CURSOR FOR
SELECT COLUMN FROM TABLEA
OPEN ACURSOR
FETCH NEXT FROM ACURSOR INTO #VAR
while ##FETCH_STATUS = 0
BEGIN
INSERT INTO TABLEB SELECT * FROM TABLEC WHERE TABLEC.COLUMNC = #VAR
DELETE TABLEF where columnf = #VAR
FETCH NEXT FROM ACURSOR INTO #VAR
END
CLOSE ACURSOR
DEALLOCATE ACURSOR
Will get x row affected for the insert and x row affected for the delete
But the actual fact is insert result cannot be seen in the physical table itself. I can see the result of I remove the Delete query. Anyone knows why?
Your code shouldn't have a cursor. You can do this:
CREATE PROCEDURE dbo.YearEndProcessing
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.TableB(column1, column2, ...)
SELECT column1, column2, ...
FROM dbo.TableA;
END
GO
Well, you changed the code, now there's a third table involved, so let me try again without a cursor:
CREATE PROCEDURE dbo.YearEndProcessing
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.TableB(column1, column2, ...)
SELECT c.column1, c.column2, ...
FROM dbo.TableA AS a
INNER JOIN dbo.TableC AS c
ON a.[Column] = c.[ColumnC];
END
GO
Or:
CREATE PROCEDURE dbo.YearEndProcessing
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.TableB(column1, column2, ...)
SELECT c.column1, c.column2, ...
FROM dbo.TableC AS c
WHERE EXISTS
(
SELECT 1 FROM dbo.TableA AS a
WHERE a.[Column] = c.[ColumnC]
);
END
GO
You shouldn't use the INSERT TABLE SELECT * FROM TABLE pattern - this is very prone to breaking in the future (see this post for more details). Also see this post about using a schema prefix and these posts about cursor usage - it should be reserved for cases that actually need it, and when you do actually need it, don't use the default options:
https://sqlblog.org/2012/01/26/bad-habits-to-kick-thinking-a-while-loop-isnt-a-cursor
http://www.sqlperformance.com/2012/07/t-sql-queries/running-totals
http://www.sqlperformance.com/2012/09/t-sql-queries/cursor-options
As for why you see rows inserted but then later can't see the data, I suspect you're looking at a table in the wrong database, in the wrong schema, or you have multiple copies of your database (which happens when you use User Instance and AttachDbFileName options in your connection string).
Related
I have a table with around 17k unique rows for which I need to run these set of statements in sequence
INSERT INTO TABLE1 using MASTERTABLE data (MASTERTABLE have 6 column)
SELECT value of column ID (Primary Key) of newly inserted row from TABLE1
Update that ID value in TABLE2 using a Stored Procedure
I have tried:
while loop: took around 3 hours to complete the execution
cursor: cancelled the query after executing it overnight
In my understanding I can not use JOIN as I need to execute the statements in a sequence
The questions is not detailed enough. The general idea I would like to use something like this
-- create a output table to hold new id, and key columns to join later
DECLARE #OutputTbl TABLE (ID INT, key_Columns in MASTERTABLE)
INSERT INTO TABLE1
OUTPUT INSERTED.ID, MASTERTABLE.key_columns INTO #OutputTbl
SELECT *
FROM MASTERTABLE
UPDATE T2
SET ID = o.ID
FROM TABLE2 t2
INNER JOIN OutputTbl o
ON t2.key_column = o.key_column
Maybe you can consider a TRIGGER on TABLE1 from which to call the stored procedure on TABLE2, and then you can call your INSERT as you wish/need.. one by one or in blocks..
DROP TRIGGER TR_UPD_TABLE2
GO
CREATE TRIGGER TR_UPD_TABLE2 ON TABLE1 AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
DECLARE #columnID INT = NULL
IF (SELECT COUNT(*) FROM INSERTED)=1 BEGIN
-- SINGLE INSERT
SET #columnID = (SELECT columnID FROM INSERTED)
EXEC TableTwoUpdateProcedure #columnID
END ELSE BEGIN
-- MASSIVE INSERT (IF NEEDED)
SET #columnID = 0
WHILE #columnID IS NOT NULL BEGIN
SET #columnID = (SELECT MIN(columnID) FROM INSERTED WHERE columnID > #columnID)
IF #columnID IS NOT NULL BEGIN
EXEC TableTwoUpdateProcedure #columnID
END
END
END
END
I have two tables with students (using Microsoft SQL Server 2008 R2 Standard edition). I Need to write a procedure, so that if 1st table has new students, the second one gets updated as well
this doesnt work and I dont know why:
CREATE PROCEDURE [dbo].[CHECK_NEW]
AS
begin transaction
declare #tempId int
declare #tempName varchar
DECLARE c1 CURSOR FOR
SELECT kId, kName
FROM table1
OPEN c1
FETCH NEXT FROM c1
INTO #tempId, #tempName
WHILE ##FETCH_STATUS = 0
BEGIN
if (SELECT sId FROM table2) NOT IN(#tempId)
insert into table(sId, name) values(#tempId, #tempName)
END
commit
Thanks in advance
Try like this....
CREATE PROCEDURE [dbo].[CHECK_NEW]
AS
Begin Try
begin transaction
Insert into Table2(ulid,Id,Name)
Select newid() as ulid, Id,name from ( Select Row_Number() over(Partition by a.id order by a.id) as row, a.Id,a.name from Table1 a where
not exists(Select * from Table2b where a.Id=b.Id)) t where row =1
Commit
End Try
Begin Catch
RollBack
End Catch
In my sql code I have declared a table(A) and inserting some rows to that table from a database table(B). Then I have to take those inserted rows from A and put it into a CURSOR and after I do a FETCH NEXT still the ##FETCH_STATUS is -1. But the expected value for the ##FETCH_STATUS is 0.
I am putting a simplified code below the question.
Can I know what is the wrong with this code. Can I use declared tables to populate the CURSORs in SQL or cursor has to be populated from a created table in the database.
// This is a code that goes inside a Stored Procedure.
AS
DECLARE A TABLE (.........)// A table has same fields in table B
DECLARE s INT
WHILE EXISTS ( SELECT * FROM B WHERE ......)
BEGIN
BEGIN TRAN
INSERT INTO A SELECT TOP 10 (....)FROM B WITH (UPDLOCK, HOLDLOCK) WHERE ....
SELECT s = count(*) from A // this returns some value which means inserting is working
DECLARE dataSet CURSOR FOR (SELECT..... FROM A)
OPEN dataSet
FETCH NEXT FROM dataSet INTO ...
WHILE ##FETCH_STATUS = 0 // coming value for this is -1
BEGIN
//Code goes here
FETCH NEXT FROM dataSet INTO ...
END
CLOSE dataSet
DEALLOCATE dataSet
DELETE FROM A
COMMIT TRAN
END
Here's a runnable version of the OPs question - but it doesn't exhibit the issue. This isn't an answer, so CW, and I'll delete if/when the OP does post an actual example:
create table B (ID int not null,Val1 varchar(10) not null)
go
insert into B(ID,Val1) values (1,'abc'),(2,'ade')
go
create procedure DoStuff
AS
DECLARE #A TABLE (ID int not null,Val1 varchar(10) not null)
DECLARE #s INT
WHILE EXISTS ( SELECT * FROM B WHERE Val1 like 'a%')
BEGIN
BEGIN TRAN
INSERT INTO #A SELECT TOP 10 ID,Val1 FROM B WITH (UPDLOCK, HOLDLOCK) WHERE Val1 like 'a%'
SELECT #s = count(*) from #A
DECLARE dataSet CURSOR FOR (SELECT ID,Val1 FROM #A)
declare #ID int
declare #Val1 varchar(10)
OPEN dataSet
FETCH NEXT FROM dataSet INTO #ID,#Val1
WHILE ##FETCH_STATUS = 0
BEGIN
RAISERROR('%i: %s',10,1,#ID,#Val1) WITH NOWAIT
UPDATE B set Val1 = 'done' where ID = #ID
FETCH NEXT FROM dataSet INTO #ID,#Val1
END
CLOSE dataSet
DEALLOCATE dataSet
DELETE FROM #A
COMMIT TRAN
END
GO
EXEC DoStuff
GO
SELECT * from B
Output:
(2 row(s) affected)
(2 row(s) affected)
1: abc
(1 row(s) affected)
2: ade
(1 row(s) affected)
(2 row(s) affected)
(2 row(s) affected)
and table B:
ID Val1
1 done
2 done
Since its uncommited transaction on table A, table A might have been locked. So for your dataset cursor try-
select '' from A with (nolock) where ...
i think create temp table then declare it for cursor, not must be have an existing table
like:
DECLARE cursor_name CURSOR FOR SELECT id INTO temp_table FROM user_id
I need to create a temporary table and then update the original table. Creating the temporary table is not a problem.
create table #mod_contact
(
id INT IDENTITY NOT NULL PRIMARY KEY,
SiteID INT,
Contact1 varchar(25)
)
INSERT INTO #mod_contact (SiteID, Contact1)
select r.id, r.Contact from dbo.table1 r where CID = 142
GO
Now I need to loop through the table and update r.contact = SiteID + r.contact
I have never used a while loop before and can't seem to make any examples I have seen work.
You can do this in multiple ways, but I think you're looking for a way using a cursor.
A cursor is sort of a pointer in a table, which when incremented points to the next record. ( it's more or less analogeous to a for-next loop )
to use a cursor you can do the following:
-- DECLARE the cursor
DECLARE CUR CURSOR FAST_FORWARD READ_ONLY FOR SELECT id, siteId, contract FROM #mod_contract
-- DECLARE some variables to store the values in
DECLARE #varId int
DECLARE #varSiteId int
DECLARE #varContract varchar(25)
-- Use the cursor
OPEN CUR
FETCH NEXT FROM CUR INTO #varId, #varSiteId, #varContract
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE dbo.table1
SET contract = #varSiteId + #varContract -- It might not work due to the different types
WHERE id = #varId
FETCH NEXT FROM CUR INTO #varId, #varSiteId, #varContract
END
CLOSE CUR
DEALLOCATE CUR
It's not the most efficient way to get this done, but I think this is what you where looking for.
Hope it helps.
Use a set based approach - no need to loop (from the little details):
UPDATE
r
SET
r.Contact = m.SiteID + r.Contact
FROM
table1 r
INNER JOIN
#mod_contact m
ON m.id=r.id
Your brain wants to do this:
while records
update(i); //update record i
records = records + 1
end while
SQL is set based and allows you to take a whole bunch of records and update them in a single command. The beauty of this is you can use the WHERE clause to filter certain rows that are not needed.
As others have mentioned, learning how to do loops in SQL is generally a bad idea; however, since you're trying to understand how to do something, here's an example:
DECLARE #id int
SELECT #ID =1
WHILE #ID <= (SELECT MAX(ID) FROM table_1)
-- while some condition is true, then do the following
--actions between the BEGIN and END
BEGIN
UPDATE table_1
SET contact = CAST(siteID as varchar(100)) + contact
WHERE table_1.CID = #ID
--increment the step variable so that the condition will eventually be false
SET #ID = #ID + 1
END
--do something else once the condition is satisfied
PRINT 'DONE!! Don't try this in production code...'
Try this one:
-- DECLARE the cursor
DECLARE CUR CURSOR FAST_FORWARD READ_ONLY FOR SELECT column1,column2 FROM table
-- DECLARE some variables to store the values in
DECLARE #varId int
DECLARE #varSiteId int
--DECLARE #varContract varchar(25)
-- Use the cursor
OPEN CUR
FETCH NEXT FROM CUR INTO #varId, #varSiteId
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT *
FROM Table2
WHERE column1 = #varId
AND column2 = #varSiteId
FETCH NEXT FROM CUR INTO #varId, #varSiteId
END
CLOSE CUR
DEALLOCATE CUR
need to create a temporary table and then up date the original table.
Why use a temporary table at all? Your CID column doesn't appear in the temporary table, so I don't see how you can successfully update the original table using SiteID, unless there is only one row where CID = 142 in which using a temp table is definitely overkill.
You can just do this:
UPDATE dbo.table1
SET contact = SiteID + contact
WHERE CID = 142;
Here's a related example which may help getting you to 'think in SQL':
UPDATE T
SET A = B, B = A;
Assuming A and B are of the same type, this would successfully swap their values.
I'm using SQL Server 2005.
I am migrating data over from a current database (single table) to a new database (normalized - many tables). In the new database, I have a base table (let's call it "BaseTable"), and multiple other tables (let's call them "DependentA", and "DependentB"). Some of the data from the old database will go to BaseTable, and some will go to the other two. BaseTable has a one-to-one relationship with both DependentA and DependentB, using the Id of them as the foreign key.
So here's my question. How should I migrate the data over? Here is a query I've been trying, which is working except for one thing: the foreign keys in BaseTable for the other two are identical, instead or having a different one each.
Begin SQL:
BEGIN TRANSACTION
DECLARE #dep1Id int
DECLARE #dep2Id int
INSERT INTO DependentA (column1, column2)
SELECT c1, c2
FROM OldDatabase.OldTable
SELECT #dep1Id = Scope_Identity()
INSERT INTO DependentB (column3, column4)
SELECT c3, c4
FROM OldDatabase.OldTable
SELECT #dep2Id = Scope_Identity()
INSERT INTO BaseTable (column5, dependentTable1Id, dependentTablr2Id)
SELECT c5, #dep1Id, #dep2Id
FROM OldDatabase.OldTable
COMMIT
The problem is that #dep1Id and #dep1Id are scalar and are retaining the last value only from the two set based inserts.
Since it's a one off you should probably do it as a cursor
DECLARE CURSOR #curs FOR
SELECT c1,c2,c3,c4,c5 FROM OldDatebase
open #curs
fetch next from #curs into
#c1,#c2,#c3,#c4,#c5 --declare these!
while ##fetch_status <> 0
BEGIN
INSERT INTO DependentA (column1, column2) VALUES #c1, #c2
SELECT #dep1Id = Scope_Identity()
INSERT INTO DependentB (column3, column4) VALUES #c3, #c4
SELECT #dep2Id = Scope_Identity()
INSERT INTO BaseTable (column5, department1Id, department2Id) #c5, #dep1Id, #dep2Id
fetch next from #curs into
#c1,#c2,#c3,#c4,#c5
END
close #curs
deallocate #curs
My cursor syntax is probably riddled with errors, but you get the idea.
To avoid a cursor for large data sets, temporarily include the OldTable_id in the new tables.
BEGIN TRANSACTION
INSERT INTO DependentA (OldTable_id, column1, column2)
SELECT ot.id, ot.c1, ot.c2
FROM OldDatabase.OldTable ot
INSERT INTO BaseTable (OldTable_id, column5)
SELECT ot.id, ot.c5
FROM OldDatabase.OldTable ot
UPDATE BaseTable
SET BaseTable.dependentTable1_id = DependentA.id
FROM BaseTable
INNER JOIN DependentA on DependentA.OldTable_id = BaseTable.OldTable_id
COMMIT
Do the same for DependentB table and any other tables being normalized out of the OldTable.
Delete OldTable_id after the data migration.
[enter image description here][1]ZeorOne is the main table from which you want to get data and insert it into zero and one table respectively.
select idzero,namezero,idone,nameone from zeroone
insert into zero
select idzero,namezero from zeroone
insert into one
select idone,nameone from zeroone
or you want to use cursor to insert data with selected columns from Zeroone
into to two tables the query is here
Declare #idzero int
Declare #namezero varchar(50)
Declare #idone int
Declare #nameone varchar(50)
Declare Cur Cursor for
select idzero,namezero,idone,nameone from zeroone
open Cur
fetch Cur into #idzero,#namezero,#idone,#nameone
While ##fetch_status = 0
begin
insert into zero
select #idzero,#namezero
insert into one
select #idone,#nameone
fetch Cur into #idzero,#namezero,#idone,#nameone
end
close Cur
Deallocate Cur
DECLARE #Product_Name varchar(50),#Generic_Name varchar(50),#Category_Name varchar(50),#Manufacture_Name varchar(50),
#UOM_Name varchar(50),#ProductId int,#GenericId int,#CategoryId int,#ManufactureId int,#UOMId int
DECLARE MultiplTable CURSOR FOR
SELECT ProductName,GenericName,CategoryName,ManufacturerName,UOMName from Noor_ProductList
open MultiplTable
fetch next from MultiplTable into
#Product_Name,#Generic_Name,#Category_Name,#Manufacture_Name,#UOM_Name --declare these!
while ##fetch_status = 0
BEGIN
INSERT INTO Noor_GenericMaster(GenericName) VALUES (#Generic_Name)
SELECT #GenericId = Scope_Identity()
INSERT INTO Noor_CategoryMaster(CategoryName) VALUES (#Category_Name)
SELECT #CategoryId = Scope_Identity()
INSERT INTO Noor_ManufaturerMaster(ManufaturerName) VALUES (#Manufacture_Name)
SELECT #ManufactureId = Scope_Identity()
INSERT INTO Noor_UOMMaster(UOMName) VALUES (#UOM_Name)
SELECT #UOMId = Scope_Identity()
INSERT INTO Noor_ProductMaster (ProductName,GenericID,CategoryID,ManufaturerID,UOMID)
values (#Product_Name,#GenericId,#CategoryId,#ManufactureId,#UOMId)
SELECT #ProductId = Scope_Identity()
fetch next from MultiplTable into #Product_Name,#Generic_Name,#Category_Name,#Manufacture_Name,#UOM_Name
END
close MultiplTable
deallocate MultiplTable