How to use output parameter with other columns names in SQL Server - sql-server

I have a simple table with columns - id, name, and salary.
I want to get the name, salary and annual salary by id using a stored procedure.
I thought of creating a simple stored procedure like this:
CREATE PROCEDURE spGetDetails
#id int,
#annualSal int out
AS
BEGIN
SELECT
name, salary,
#annualSal = (salary * 12)
FROM
tblPrac
WHERE
id = #id
END
But I'm getting an error:
A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations
If this qs is already asked please give me the link and I'll delete this qs. I searched but I think I'm missing the key word. Thanks

You don't need an OUTPUT parameter. You can simply query like this -
CREATE PROCEDURE spGetDetails
#id int
AS
BEGIN
SET NOCOUNT ON
SELECT Name, Salary, (Salary*12) AS AnnualSalary FROM tblPrac WHERE id = #id
END

You have stuff mixed so you need to choose between 2 possibilities
CREATE PROCEDURE spGetDetails
#id int,
#name varchar(100) out,
#salary decimal(16,2) out,
#annualSal decimal(16,2) out
AS
BEGIN
set nocount on
SELECT #name = name,
#salary = salary,
#annualSal = (salary * 12)
FROM tblPrac
WHERE id = #id
END
or this
CREATE PROCEDURE spGetDetails
#id int
AS
BEGIN
set nocount on
SELECT name,
salary,
(salary * 12) as anualSal
FROM tblPrac
WHERE id = #id
END

You need to store the data and separate the operations (as the error message is explaining):
CREATE PROCEDURE spGetDetails
(
#id int,
#annualSal int out
)
AS
BEGIN;
SET NOCOUNT ON;
DECLARE #DataSource TABLE
(
[name] VARCHAR(12)
,[salary] DECIMAL(9,2)
);
INSERT INTO #DataSource ([name], [salary])
SELECT name, salary
FROM tblPrac
WHERE id = #id;
SELECT [name]
,[salary]
FROM #DataSource;
SELECT #annualSal = 12 * [salary]
FROM #DataSource;
SET NOCOUNT OFF;
RETURN;
END;

Related

SQL Server create Triggers on INSERT and SELECT OUTCOME

I try to create a Trigger that will insert a Unique ID in a table and then get the created ID and use it on the table that "Triggered the trigger"
So I insert some data in my table and then I want the trigger to insert some data in another table (master ID table), it then needs to get the just created ID (auto increment INT) and add this ID to the table ID that the trigger fired on.
I tried quite some different options but it just does not insert the ID and it will give me an error.
Hope you can help me out.
CREATE TRIGGER [dbo].[TROidMemoDiaryHeader]
ON [dbo].[InvoiceDiaryHeader]
FOR INSERT
AS
DECLARE #TEMP uniqueidentifier, #Lock INT, #Object INT, #User V ARCHAR(MAX), #Delay NCHAR(12), #ID INT
SET #TEMP = NEWID()
SET #Lock = '0' --staat geen wijziging meer toe
SET #Object = '5' -- aanduiding bron
SET #User = CURRENT_USER
--SET #Delay = '00:00:00:125' -- Wacht voor een kwart seconde voor verder te gaan
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
--SET NOCOUNT ON;
INSERT INTO [dbo].[AbstractMBOBase] ([Uid], [OptimisticLockField], [ObjectType], [User])
SELECT #TEMP, #Lock, #Object, #User
IF EXISTS (SELECT [Uid] FROM [dbo].AbstractMBOBase WHERE [Uid] = #TEMP)
BEGIN
INSERT INTO [InvoiceDiaryHeader](Oid)
SELECT Oid FROM inserted
/*
SELECT * INTO #tmpOID FROM AbstractMBOBase WHERE [Uid] = #TEMP
UPDATE [dbo].InvoiceDiaryHeader SET Oid = (SELECT a.[Oid] FROM [dbo].[AbstractMBOBase] AS a
WHERE [Uid] = #TEMP)
--CREATE TABLE [dbo].#TempOID()
--SELECT * INTO #TempOID FROM INSERTED
*/
/*
--UPDATE [MemoDiaryHeader]
SET #ID = (SELECT a.[Oid] FROM [dbo].[AbstractMBOBase] AS a
WHERE [Uid] = #TEMP)
INSERT INTO [MemoDiaryHeader]([Oid])
SELECT #ID
--FROM inserted
--select [Oid]=i.[Oid] from inserted i
*/
END
--END
END
GO

How to update N rows when N is in a from (select N from #myVar)

I'm developing this stored procedure on SQL Server 2012.
The stored procedure will update Quantity rows in EXTERNAL_CODES table for each row in #newBatches parameter. It's like a loop, I will need to create a new row in BATCHES table for each row in #newBatches parameter.
And then, I have to update Quantity rows in EXTERNAL_CODES table with each batchId created.
CREATE PROCEDURE [dbo].[CreateBatchAndKeepExternalCodes]
#newBatches as dbo.CreateBatchList READONLY,
#productId int
AS
set nocount on;
declare #lowestCodeLevel tinyint;
-- ======== VALIDATION ==========
if ((select count(name) from #newBatches) = 0)
return -112;
-- ====== CODE ========
-- Get lowest aggregation level.
set #lowestCodeLevel =
(select min(c.application_code)
from CHINA_CODES_HEADER c, PRODUCTS p
where p.Id = #productId and c.DRUG_TEN_SEATS = p.PRODUCT_CODE);
begin transaction;
insert into BATCHES (PRODUCT_ID, NAME, CREATED)
select #productId, Name, CAST(SYSDATETIMEOFFSET() as nvarchar(50))
from #newBatches;
update top(t.Quantity) EXTERNAL_CODES
set BATCH_ID = (select ID from BATCHES where NAME = t.Name)
, USED = 1
from (select Name, Quantity from #newBatches) t
where PRODUCT_ID = #productId and CODE_LEVEL = #lowestCodeLevel;
commit transaction;
RETURN 0
I get an error on this update:
update top(t.Quantity) EXTERNAL_CODES
set BATCH_ID = (select ID from BATCHES where NAME = t.Name)
, USED = 1
from (select Name, Quantity from #newBatches) t
where PRODUCT_ID = #productId and CODE_LEVEL = #lowestCodeLevel;
The error is here: update top(t.Quantity). It can't find t.Quantity.
dbo.CreateBatchList is:
CREATE TYPE [dbo].[CreateBatchList] AS TABLE
(
Name nVARCHAR(20),
Quantity int
)
My problem is that I can't set to update Quantity rows. Any idea?
The error (or warning) message is:
SQL71005: The reference to the column t.Quantity could not be resolved.
Maybe I could use MERGE.
Your update statement is quite confusing. If for instance #newBatches table has multiple lines, then you are saying, pick all the Quantity from #newBatches in Top?
Anyway, I think the solution is to use a loop to use each line from #newBatches to update. I have modified your code in order to test it on my side, and have replaced all the tables with Table Variables. You may find it helpful.
But still without any Order By clause and without knowing actual business logic, I can't say this solution is correct.
DECLARE #productID int;
DECLARE #lowestCodeLevel int;
DECLARE #EXTERNAL_CODES table(BATCH_ID varchar(100), USED bit, PRODUCT_ID int, CODE_LEVEL int);
DECLARE #BATCHES table(ID int, NAME varchar(100));
DECLARE #newBatches table(Name nVARCHAR(20), Quantity int);
-- we don't know at this point whether #newBatches has some column
-- through which we can uniquely identify a row
-- that is why we are creating this new table in which we have Row_ID column
-- through which we can extract each line
DECLARE #newBatchesWithRowID table(Row_ID int not null identity, Name nVarchar(20), Quantity int);
INSERT INTO #newBatchesWithRowID(Name, Quantity)
SELECT Name, Quantity
FROM #newBatches;
DECLARE #prvRow_ID int;
-- loop to iterate in #newBatchesWithRowID table
WHILE(1 = 1)
Begin
DECLARE #row_ID int = NULL;
DECLARE #Name varchar(100);
DECLARE #Quantity int;
SELECT TOP 1 #row_ID = Row_ID
, #Quantity = Quantity
, #Name = Name
FROM #newBatchesWithRowID
WHERE Row_ID > #prvRow_ID OR #prvRow_ID IS NULL
ORDER BY Row_ID;
If #row_ID IS NULL Break;
SET #prvRow_ID = #row_ID;
update top(#Quantity) #EXTERNAL_CODES
set BATCH_ID = (select ID from #BATCHES where NAME = #Name)
, USED = 1
where PRODUCT_ID = #productId and CODE_LEVEL = #lowestCodeLevel;
END

Triggers not working when inserting data through OPEN XML in sql ser

I have created a trigger for a asset_verification. Whenever a new record is inserted in this table, the same record is inserted in the asset_verification_history table because of this trigger.
The trigger is as follows
Create trigger [dbo].[tr_insert_after_asset_verification] on [dbo].[asset_verification]
for insert
As
Begin
declare #verification_id int
declare #id int
declare #audit_id int
declare #date date
declare #status varchar(15)
declare #remarks varchar(200)
declare #creationDate datetime
declare #modificationDate datetime
declare #updatedBy int
declare #audit_action varchar(20)
Select #verification_id = i.verification_id from inserted i
If #verification_id IS NOT NULL
Begin
Select #id = i.id from inserted i
Select #audit_id = i.audit_id from inserted i
Select #date = i.date from inserted i
Select #status = i.status from inserted i
Select #remarks = i.remarks from inserted i
Select #creationDate = i.creationDate from inserted i
Select #modificationDate = i.modificationDate from inserted i
Select #updatedBy = i.updatedBy from inserted i
set #audit_action = 'Insert Record'
INSERT INTO [dbo].[asset_verification_history]
([verification_id]
,[id]
,[audit_id]
,[date]
,[status]
,[remarks]
,[creationDate]
,[modificationDate]
,[updatedBy]
,[audit_action])
VALUES
(#verification_id
,#id
,#audit_id
,#date
,#status
,#remarks
,#creationDate
,#modificationDate
,#updatedBy
,#audit_action)
End
End
When I insert the data in the asset_verification table using a procedure in which OPEN XML is used, then this trigger works only for the first record. For the rest of the records the trigger doesn't work
The procedure is as follows
Create procedure [dbo].[usp_AddVerificationBulkData]
(
#vXML XML
)
As
Begin
DECLARE #DocHandle INT
SET NOCOUNT ON
EXEC sp_xml_preparedocument #DocHandle OUTPUT, #vXML
Update asset_verification
set
audit_id = x.AuditId,
id = x.SerialId,
date = x.VerificationDate,
status = x.Status
,remarks = x.Remarks
,creationDate = x.CreatedOn
,modificationDate = x.ModifiedOn
,updatedBy = x.ModifiedBy
From
asset_verification a
Inner Join
OpenXml(#DocHandle,'/ArrayOfAssetVerificationModel/AssetVerificationModel',2)
With(SerialId int, AuditId int, VerificationDate datetime, Status int, Remarks varchar(200), CreatedOn datetime, ModifiedOn datetime, ModifiedBy int) x
On a.audit_id = x.AuditId where a.id = x.SerialId;
INSERT INTO [dbo].[asset_verification]
([id]
,[audit_id]
,[date]
,[status]
,[remarks]
,[creationDate]
,[modificationDate]
,[updatedBy])
select SerialId,AuditId,VerificationDate,Status,Remarks,CreatedOn,ModifiedOn,ModifiedBy from OpenXml(#DocHandle,'/ArrayOfAssetVerificationModel/AssetVerificationModel',2)
With(SerialId int, AuditId int, VerificationDate datetime, Status int, Remarks varchar(200), CreatedOn datetime, ModifiedOn datetime, ModifiedBy int) x
where SerialId NOT IN (select a.id from asset_verification a where a.audit_id = x.AuditId);
End
Problem:- How to make this trigger work for every record that is inserted through Open XML ?
You've made the classic mistake of thinking that triggers fire once-per-row. They dont, it's once-per-action, so the inserted pseudo table holds all the rows affected by the action. Your trigger needs to work in a set based manner, not row based. Try this;
CREATE TRIGGER [dbo].[tr_insert_after_asset_verification] ON [dbo].[asset_verification] FOR INSERT AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[asset_verification_history]
( [verification_id]
,[id]
,[audit_id]
,[date]
,[status]
,[remarks]
,[creationDate]
,[modificationDate]
,[updatedBy]
,[audit_action]
)
SELECT i.verification_id
,i.id
,i.audit_id
,i.date
,i.status
,i.remarks
,i.creationDate
,i.modificationDate
,i.updatedBy
,'Insert Record'
FROM inserted i
WHERE i.verification_id IS NOT NULL
END
As an aside, and strictly speaking, your original trigger will log one row, not necessarily the first.

jdbc sql error: statement did not return a result set

I have two stored procedures as follows:
create stored procedure p1
as
select * from table1 where datediff(day, table1.[date], getdate())
create stored procedure p2
as
declare #t1 table(
ref varchar(20)
)
insert into #t1 select * from table1 where ref = 'some ref'
declare #t2 table(
fname varchar(20),
lname varchar(20),
email varchar(1000)
)
declare #len int = (select count(ref) from #t1)
while #len > 0
begin
declare #value varchar(20) = (select top 1 ref from #t1)
insert into #t2 select * from table2 where ref = #ref
delete from #t1
where ref = #value
set #len = (select count(ref) from #t1)
end
select * from #t2
Java code
....
String query = "Execute [p2]";
try(CallableStatement cstmt = conn.prepareCall(query);
ResultSet rs = cstmt.executeQuery()){
... some code
}
The table variable #t1 hold select result from a table 'table1'
The variable #len hold the number of rows in #t1
Using #len > 0 as condition in while loop, I want to select records from another table 'table2' the table variable #t2 hold the select records from 'table2'
The delete statement removes value from #t1
#len set to new number of rows in #t1
the last statement return all the records store in #t2
The first procedure works fine, but the second procedure works only in SQL Server.
I get this an error message in my java application
statement did not return a resultset
I want this to return a result set with the select statement I have at the
end of the query.
Please is there a way around this?
Your [p2] stored procedure needs to include SET NOCOUNT ON right at the beginning to suppress the "n rows affected" counts so JDBC doesn't get confused as to what it should put into the ResultSet:
CREATE PROCEDURE p2
AS
SET NOCOUNT ON;
declare #t1 table(
ref varchar(20)
)
-- ... and so on
For more information on SET NOCOUNT see
SET NOCOUNT (Transact-SQL)
For more information on precisely what gets returned from a stored procedure call, see
How to get everything back from a stored procedure using JDBC
use method "execute" instead of "executeQuery".

Is there a way to loop through a table variable in TSQL without using a cursor?

Let's say I have the following simple table variable:
declare #databases table
(
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into #databases
Is declaring and using a cursor my only option if I wanted to iterate through the rows? Is there another way?
First of all you should be absolutely sure you need to iterate through each row — set based operations will perform faster in every case I can think of and will normally use simpler code.
Depending on your data it may be possible to loop using just SELECT statements as shown below:
Declare #Id int
While (Select Count(*) From ATable Where Processed = 0) > 0
Begin
Select Top 1 #Id = Id From ATable Where Processed = 0
--Do some processing here
Update ATable Set Processed = 1 Where Id = #Id
End
Another alternative is to use a temporary table:
Select *
Into #Temp
From ATable
Declare #Id int
While (Select Count(*) From #Temp) > 0
Begin
Select Top 1 #Id = Id From #Temp
--Do some processing here
Delete #Temp Where Id = #Id
End
The option you should choose really depends on the structure and volume of your data.
Note: If you are using SQL Server you would be better served using:
WHILE EXISTS(SELECT * FROM #Temp)
Using COUNT will have to touch every single row in the table, the EXISTS only needs to touch the first one (see Josef's answer below).
Just a quick note, if you are using SQL Server (2008 and above), the examples that have:
While (Select Count(*) From #Temp) > 0
Would be better served with
While EXISTS(SELECT * From #Temp)
The Count will have to touch every single row in the table, the EXISTS only needs to touch the first one.
This is how I do it:
declare #RowNum int, #CustId nchar(5), #Name1 nchar(25)
select #CustId=MAX(USERID) FROM UserIDs --start with the highest ID
Select #RowNum = Count(*) From UserIDs --get total number of records
WHILE #RowNum > 0 --loop until no more records
BEGIN
select #Name1 = username1 from UserIDs where USERID= #CustID --get other info from that row
print cast(#RowNum as char(12)) + ' ' + #CustId + ' ' + #Name1 --do whatever
select top 1 #CustId=USERID from UserIDs where USERID < #CustID order by USERID desc--get the next one
set #RowNum = #RowNum - 1 --decrease count
END
No Cursors, no temporary tables, no extra columns.
The USERID column must be a unique integer, as most Primary Keys are.
Define your temp table like this -
declare #databases table
(
RowID int not null identity(1,1) primary key,
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into #databases
Then do this -
declare #i int
select #i = min(RowID) from #databases
declare #max int
select #max = max(RowID) from #databases
while #i <= #max begin
select DatabaseID, Name, Server from #database where RowID = #i --do some stuff
set #i = #i + 1
end
Here is how I would do it:
Select Identity(int, 1,1) AS PK, DatabaseID
Into #T
From #databases
Declare #maxPK int;Select #maxPK = MAX(PK) From #T
Declare #pk int;Set #pk = 1
While #pk <= #maxPK
Begin
-- Get one record
Select DatabaseID, Name, Server
From #databases
Where DatabaseID = (Select DatabaseID From #T Where PK = #pk)
--Do some processing here
--
Select #pk = #pk + 1
End
[Edit] Because I probably skipped the word "variable" when I first time read the question, here is an updated response...
declare #databases table
(
PK int IDENTITY(1,1),
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into #databases
--/*
INSERT INTO #databases (DatabaseID, Name, Server) SELECT 1,'MainDB', 'MyServer'
INSERT INTO #databases (DatabaseID, Name, Server) SELECT 1,'MyDB', 'MyServer2'
--*/
Declare #maxPK int;Select #maxPK = MAX(PK) From #databases
Declare #pk int;Set #pk = 1
While #pk <= #maxPK
Begin
/* Get one record (you can read the values into some variables) */
Select DatabaseID, Name, Server
From #databases
Where PK = #pk
/* Do some processing here */
/* ... */
Select #pk = #pk + 1
End
If you have no choice than to go row by row creating a FAST_FORWARD cursor. It will be as fast as building up a while loop and much easier to maintain over the long haul.
FAST_FORWARD
Specifies a FORWARD_ONLY, READ_ONLY cursor with performance optimizations enabled. FAST_FORWARD cannot be specified if SCROLL or FOR_UPDATE is also specified.
This will work in SQL SERVER 2012 version.
declare #Rowcount int
select #Rowcount=count(*) from AddressTable;
while( #Rowcount>0)
begin
select #Rowcount=#Rowcount-1;
SELECT * FROM AddressTable order by AddressId desc OFFSET #Rowcount ROWS FETCH NEXT 1 ROWS ONLY;
end
Another approach without having to change your schema or using temp tables:
DECLARE #rowCount int = 0
,#currentRow int = 1
,#databaseID int
,#name varchar(15)
,#server varchar(15);
SELECT #rowCount = COUNT(*)
FROM #databases;
WHILE (#currentRow <= #rowCount)
BEGIN
SELECT TOP 1
#databaseID = rt.[DatabaseID]
,#name = rt.[Name]
,#server = rt.[Server]
FROM (
SELECT ROW_NUMBER() OVER (
ORDER BY t.[DatabaseID], t.[Name], t.[Server]
) AS [RowNumber]
,t.[DatabaseID]
,t.[Name]
,t.[Server]
FROM #databases t
) rt
WHERE rt.[RowNumber] = #currentRow;
EXEC [your_stored_procedure] #databaseID, #name, #server;
SET #currentRow = #currentRow + 1;
END
You can use a while loop:
While (Select Count(*) From #TempTable) > 0
Begin
Insert Into #Databases...
Delete From #TempTable Where x = x
End
Lightweight, without having to make extra tables, if you have an integer ID on the table
Declare #id int = 0, #anything nvarchar(max)
WHILE(1=1) BEGIN
Select Top 1 #anything=[Anything],#id=#id+1 FROM Table WHERE ID>#id
if(##ROWCOUNT=0) break;
--Process #anything
END
I really do not see the point why you would need to resort to using dreaded cursor.
But here is another option if you are using SQL Server version 2005/2008
Use Recursion
declare #databases table
(
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
--; Insert records into #databases...
--; Recurse through #databases
;with DBs as (
select * from #databases where DatabaseID = 1
union all
select A.* from #databases A
inner join DBs B on A.DatabaseID = B.DatabaseID + 1
)
select * from DBs
-- [PO_RollBackOnReject] 'FININV10532'
alter procedure PO_RollBackOnReject
#CaseID nvarchar(100)
AS
Begin
SELECT *
INTO #tmpTable
FROM PO_InvoiceItems where CaseID = #CaseID
Declare #Id int
Declare #PO_No int
Declare #Current_Balance Money
While (Select ROW_NUMBER() OVER(ORDER BY PO_LineNo DESC) From #tmpTable) > 0
Begin
Select Top 1 #Id = PO_LineNo, #Current_Balance = Current_Balance,
#PO_No = PO_No
From #Temp
update PO_Details
Set Current_Balance = Current_Balance + #Current_Balance,
Previous_App_Amount= Previous_App_Amount + #Current_Balance,
Is_Processed = 0
Where PO_LineNumber = #Id
AND PO_No = #PO_No
update PO_InvoiceItems
Set IsVisible = 0,
Is_Processed= 0
,Is_InProgress = 0 ,
Is_Active = 0
Where PO_LineNo = #Id
AND PO_No = #PO_No
End
End
It's possible to use a cursor to do this:
create function [dbo].f_teste_loop
returns #tabela table
(
cod int,
nome varchar(10)
)
as
begin
insert into #tabela values (1, 'verde');
insert into #tabela values (2, 'amarelo');
insert into #tabela values (3, 'azul');
insert into #tabela values (4, 'branco');
return;
end
create procedure [dbo].[sp_teste_loop]
as
begin
DECLARE #cod int, #nome varchar(10);
DECLARE curLoop CURSOR STATIC LOCAL
FOR
SELECT
cod
,nome
FROM
dbo.f_teste_loop();
OPEN curLoop;
FETCH NEXT FROM curLoop
INTO #cod, #nome;
WHILE (##FETCH_STATUS = 0)
BEGIN
PRINT #nome;
FETCH NEXT FROM curLoop
INTO #cod, #nome;
END
CLOSE curLoop;
DEALLOCATE curLoop;
end
I'm going to provide the set-based solution.
insert #databases (DatabaseID, Name, Server)
select DatabaseID, Name, Server
From ... (Use whatever query you would have used in the loop or cursor)
This is far faster than any looping techique and is easier to write and maintain.
I prefer using the Offset Fetch if you have a unique ID you can sort your table by:
DECLARE #TableVariable (ID int, Name varchar(50));
DECLARE #RecordCount int;
SELECT #RecordCount = COUNT(*) FROM #TableVariable;
WHILE #RecordCount > 0
BEGIN
SELECT ID, Name FROM #TableVariable ORDER BY ID OFFSET #RecordCount - 1 FETCH NEXT 1 ROW;
SET #RecordCount = #RecordCount - 1;
END
This way I don't need to add fields to the table or use a window function.
I agree with the previous post that set-based operations will typically perform better, but if you do need to iterate over the rows here's the approach I would take:
Add a new field to your table variable (Data Type Bit, default 0)
Insert your data
Select the Top 1 Row where fUsed = 0 (Note: fUsed is the name of the field in step 1)
Perform whatever processing you need to do
Update the record in your table variable by setting fUsed = 1 for the record
Select the next unused record from the table and repeat the process
DECLARE #databases TABLE
(
DatabaseID int,
Name varchar(15),
Server varchar(15),
fUsed BIT DEFAULT 0
)
-- insert a bunch rows into #databases
DECLARE #DBID INT
SELECT TOP 1 #DBID = DatabaseID from #databases where fUsed = 0
WHILE ##ROWCOUNT <> 0 and #DBID IS NOT NULL
BEGIN
-- Perform your processing here
--Update the record to "used"
UPDATE #databases SET fUsed = 1 WHERE DatabaseID = #DBID
--Get the next record
SELECT TOP 1 #DBID = DatabaseID from #databases where fUsed = 0
END
Step1: Below select statement creates a temp table with unique row number for each record.
select eno,ename,eaddress,mobno int,row_number() over(order by eno desc) as rno into #tmp_sri from emp
Step2:Declare required variables
DECLARE #ROWNUMBER INT
DECLARE #ename varchar(100)
Step3: Take total rows count from temp table
SELECT #ROWNUMBER = COUNT(*) FROM #tmp_sri
declare #rno int
Step4: Loop temp table based on unique row number create in temp
while #rownumber>0
begin
set #rno=#rownumber
select #ename=ename from #tmp_sri where rno=#rno **// You can take columns data from here as many as you want**
set #rownumber=#rownumber-1
print #ename **// instead of printing, you can write insert, update, delete statements**
end
This approach only requires one variable and does not delete any rows from #databases. I know there are a lot of answers here, but I don't see one that uses MIN to get your next ID like this.
DECLARE #databases TABLE
(
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into #databases
DECLARE #CurrID INT
SELECT #CurrID = MIN(DatabaseID)
FROM #databases
WHILE #CurrID IS NOT NULL
BEGIN
-- Do stuff for #CurrID
SELECT #CurrID = MIN(DatabaseID)
FROM #databases
WHERE DatabaseID > #CurrID
END
Here's my solution, which makes use of an infinite loop, the BREAK statement, and the ##ROWCOUNT function. No cursors or temporary table are necessary, and I only need to write one query to get the next row in the #databases table:
declare #databases table
(
DatabaseID int,
[Name] varchar(15),
[Server] varchar(15)
);
-- Populate the [#databases] table with test data.
insert into #databases (DatabaseID, [Name], [Server])
select X.DatabaseID, X.[Name], X.[Server]
from (values
(1, 'Roger', 'ServerA'),
(5, 'Suzy', 'ServerB'),
(8675309, 'Jenny', 'TommyTutone')
) X (DatabaseID, [Name], [Server])
-- Create an infinite loop & ensure that a break condition is reached in the loop code.
declare #databaseId int;
while (1=1)
begin
-- Get the next database ID.
select top(1) #databaseId = DatabaseId
from #databases
where DatabaseId > isnull(#databaseId, 0);
-- If no rows were found by the preceding SQL query, you're done; exit the WHILE loop.
if (##ROWCOUNT = 0) break;
-- Otherwise, do whatever you need to do with the current [#databases] table row here.
print 'Processing #databaseId #' + cast(#databaseId as varchar(50));
end
This is the code that I am using 2008 R2. This code that I am using is to build indexes on key fields (SSNO & EMPR_NO) n all tales
if object_ID('tempdb..#a')is not NULL drop table #a
select 'IF EXISTS (SELECT name FROM sysindexes WHERE name ='+CHAR(39)+''+'IDX_'+COLUMN_NAME+'_'+SUBSTRING(table_name,5,len(table_name)-3)+char(39)+')'
+' begin DROP INDEX [IDX_'+COLUMN_NAME+'_'+SUBSTRING(table_name,5,len(table_name)-3)+'] ON '+table_schema+'.'+table_name+' END Create index IDX_'+COLUMN_NAME+'_'+SUBSTRING(table_name,5,len(table_name)-3)+ ' on '+ table_schema+'.'+table_name+' ('+COLUMN_NAME+') ' 'Field'
,ROW_NUMBER() over (order by table_NAMe) as 'ROWNMBR'
into #a
from INFORMATION_SCHEMA.COLUMNS
where (COLUMN_NAME like '%_SSNO_%' or COLUMN_NAME like'%_EMPR_NO_')
and TABLE_SCHEMA='dbo'
declare #loopcntr int
declare #ROW int
declare #String nvarchar(1000)
set #loopcntr=(select count(*) from #a)
set #ROW=1
while (#ROW <= #loopcntr)
begin
select top 1 #String=a.Field
from #A a
where a.ROWNMBR = #ROW
execute sp_executesql #String
set #ROW = #ROW + 1
end
SELECT #pk = #pk + 1
would be better:
SET #pk += #pk
Avoid using SELECT if you are not referencing tables are are just assigning values.

Resources