I want to use Cursor with dynamic SchemaName.
In my below Code SELECT id FROM #schema_names.company line is my issue. #schema_names is dynamic Schema Name.
How to use Dynamic Schema/Table Name in Cursor?
-- in-memory schema table to hold distinct schema_names
DECLARE #i int
DECLARE #numrows int
DECLARE #schema_names nvarchar(max)
DECLARE #schema_table TABLE (
idx smallint Primary Key IDENTITY(1,1)
, schema_names nvarchar(max)
)
DECLARE #company_id NVARCHAR(max)
-- populate schema table
INSERT #schema_table
SELECT name FROM sys.schemas Where name <> 'dbo' AND name <> 'guest' AND name <> 'INFORMATION_SCHEMA' AND name <> 'db_accessadmin' AND name <> 'db_backupoperator' AND name <> 'db_datareader' AND name <> 'db_datawriter' AND name <> 'db_ddladmin' AND name <> 'db_denydatareader' AND name <> 'db_denydatawriter' AND name <> 'db_owner' AND name <> 'db_securityadmin' AND name <> 'sys'
select * from #schema_table
-- enumerate the table
SET #i = 1
SET #numrows = (SELECT COUNT(*) FROM #schema_table)
IF #numrows > 0
WHILE (#i <= (SELECT MAX(idx) FROM #schema_table))
BEGIN
-- get the next record primary key
SET #schema_names = (SELECT schema_names FROM #schema_table WHERE idx = #i)
DECLARE my_cursor CURSOR local static read_only forward_only FOR
SELECT id FROM #schema_names.company
OPEN my_cursor
FETCH next FROM my_cursor INTO #company_id
WHILE ##FETCH_STATUS = 0
BEGIN
--Do something with Id here
PRINT #company_id + 'a'
FETCH next FROM my_cursor INTO #company_id
END
CLOSE my_cursor
DEALLOCATE my_cursor
BEGIN TRY
DECLARE #sSQL nvarchar(500);
SELECT #sSQL = N'INSERT ['+#schema_names+'].[Menu] VALUES (9, N''Dashboard'', N''Charts'', N''/Dash/Chart'', 1)'
EXEC sp_executesql #sSQL
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE()+' '+#schema_names AS ErrorMessage;
END CATCH
-- increment counter for next record
SET #i = #i + 1
END
try This approach
1 - Create a Temp Table
2 - Insert the Id from your Table to the Temp table using Dynamic SQL
3 - Fetch Cursor from Temp Table
CREATE TABLE #Temp
(
Id INT
)
SET #schema_names =
(
SELECT
schema_names
FROM #schema_table
WHERE idx = #i
)
TRUNCATE TABLE #temp
INSERT INTO #temp(Id)
EXEC('SELECT id FROM '+#schema_names+'.company;')
DECLARE my_cursor CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT ID FROM #TEMP
OPEN my_cursor;
FETCH NEXT FROM my_cursor INTO #company_id;
Related
I am writing an exe string in sql 2012 and I am getting the following error.
Incorrect syntax near Group By. Any assistance would be much appreciated in advance.
declare #counter int = (select count(1) from #temp) SELECT * FROM #temp
declare #tab_name varchar(100)
declare #col_name varchar(100)
while (#counter > 0)
begin
set #tab_name = (select table_name from #temp where rn = #counter)
set #col_name = (select field_name from #temp where rn = #counter)
exec ('select
'''+#tab_name+''','''+#col_name+''',max(len('+#col_name+')),'''+#col_name+'''
from [x3v7].[LIVE].'+#tab_name+'''Group By'''+#col_name+'''Having
max(len('+#col_name+'))>12''')
set #counter -= 1
end
Here's a the basic structure of a cursor loop with dynamic SQL to get you started.
The string concatenation is still a mess. Clean it up using the CONCAT and QUOTENAME functions to generate the query.
declare #tab_name varchar(100)
declare #col_name varchar(100)
declare c cursor local for
select table_name, field_name
from #temp
open c;
fetch next from c into #tab_name, #col_name;
while ##FETCH_STATUS = 0
begin
declare #sql nvarchar(max) = 'select
'''+#tab_name+''','''+#col_name+''',max(len('+#col_name+')),'''+#col_name+'''
from [x3v7].[LIVE].'+#tab_name+'''Group By'''+#col_name+'''Having
max(len('+#col_name+'))>12'''
print #sql
--exec(#sql);
fetch next from c into #tab_name, #col_name
end
close c;
deallocate c;
I am making a script that prints tablenames into a temp table.
I need it to place a suffix to the end like this
#temptable1
#temptable2
...
#temptableXXX
My problem is it doesn't increment when I use rank, and identity doesn't work in a cursor.
I have posted both tries. One of them are commented out.
DECLARE #suffix VARCHAR(1000)
DECLARE #crs insensitive CURSOR FOR
SELECT IDENTITY(int, 1, 1) AS ID --rank() over (partition by name order by
name) --as Identity(1,1)
INTO name
FROM sys.tables
FOR READ ONLY
OPEN #crs
FETCH NEXT FROM #crs INTO #suffix
WHLIE ##FETCH_STATUS = 0
BEGIN
DECLARE #TableName VARCHAR(100)
DECLARE #TabName CURSOR
SET #TabName = CURSOR FOR
SELECT NAME + #suffix
FROM sys.tables
ORDER BY name
OPEN #TabName
PRINT '--- Her skal header printes '
FETCH NEXT FROM #TabName INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #TableName
----------------------------------------------------------------- start loop tabel
----------------------------------------------------------------- slut loop tabel
Fetch next from #TabName into #TableName
END
CLOSE #TabName;
DEALLOCATE #TabName;
END
CLOSE #crs
DEALLOCATE #crs
I think you are just looking for
SELECT CONCAT(Name, ROW_NUMBER() OVER(ORDER BY Name)) TableName
FROM Sys.Tables;
First, don't use a cursor :) I'd do something like this:
DECLARE
#Table_Name As Varchar(200)
, #Message As VarChar(Max)
, #Suffix As Int = 1
, #Temp_Table_Name As Varchar(100)
Select Distinct
name
, 0 As Processed
Into #Temp_Names
from sys.tables
While Exists (Select Top 1 1
FROM #Temp_Names
WHERE Processed = 0)
BEGIN
Select Top 1
#Table_Name = name
From #Temp_Names
WHERE Processed = 0
Set #Temp_Table_Name = 'TempTable' + Cast(#Suffix As Varchar(100))
/*
your code here
*/
Update #Temp_Names
Set Processed = 1
Where name = #Table_Name
Set #Suffix = #Suffix + 1
End
You may want to adjust the Varchar sizes - I was shooting from the hip.
Try this-
SELECT NAME+CAST(RANK() OVER(ORDER BY NAME) AS VARCHAR) AS NEW_NAME
FROM SYS.TABLES
Another solution to the problem is this.
declare #nr int = 0;
set #nr = #nr +1 ;
#TmpTab_'+CONVERT(nvarchar(3), #nr)+'
In my Database I have various Schemas & every Schema have a Table as [Company] & Other Tables.
I have written below Query which iterates all Schemas & in case i want to INSERT something in a Table for all Schemas I run this Query.
I am stuck in a Scenario where Insert Query requires Values from a [Company] Table.
Example - In 1 Schema I have [Company] Table & I have 4 Records in it.
So I want to INSERT 4 Records in [Menu] Table & Company Id will be picked from [Company] Table.
Right Now, In the below Query I am just Selecting Id from [Company] table.
I want to know How to iterate through the Records of Select Statement?
-- in-memory schema table to hold distinct schema_names
DECLARE #i int
DECLARE #numrows int
DECLARE #schema_names nvarchar(max)
DECLARE #schema_table TABLE (
idx smallint Primary Key IDENTITY(1,1)
, schema_names nvarchar(max)
)
DECLARE #company_table nvarchar(max)
DECLARE #sql nvarchar(max)
-- populate schema table
INSERT #schema_table
SELECT name FROM sys.schemas Where name <> 'dbo' AND name <> 'guest' AND name <> 'INFORMATION_SCHEMA' AND name <> 'db_accessadmin' AND name <> 'db_backupoperator' AND name <> 'db_datareader' AND name <> 'db_datawriter' AND name <> 'db_ddladmin' AND name <> 'db_denydatareader' AND name <> 'db_denydatawriter' AND name <> 'db_owner' AND name <> 'db_securityadmin' AND name <> 'sys'
select * from #schema_table
-- enumerate the table
SET #i = 1
SET #numrows = (SELECT COUNT(*) FROM #schema_table)
IF #numrows > 0
WHILE (#i <= (SELECT MAX(idx) FROM #schema_table))
BEGIN
-- get the next record primary key
SET #schema_names = (SELECT schema_names FROM #schema_table WHERE idx = #i)
SET #company_table = '['+#schema_names+'].[Company]'
SET #sql = 'select Id from ' + #company_table
EXEC(#sql)
BEGIN TRY
DECLARE #sSQL nvarchar(500);
SELECT #sSQL = N'INSERT ['+#schema_names+'].[Menu] VALUES (9, N''Dashboard'', N''Charts'', N''/Dash/Chart'', 1)'
EXEC sp_executesql #sSQL
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE()+' '+#schema_names AS ErrorMessage;
END CATCH
-- increment counter for next record
SET #i = #i + 1
END
In this Query - 9 will be replaced by Value from [Company] Table.
Just it simple for iterating in each row you can use the below Example
CREATE PROCEDURE cursor1()
BEGIN
DECLARE finished INTEGER DEFAULT 0;
DECLARE fname1 CHAR(20) DEFAULT "";
DECLARE lname1 CHAR(20) DEFAULT "";
DECLARE nameList CHAR(100) DEFAULT "";
-- 1. Declare cursor for employee
DECLARE emp_cursor CURSOR FOR SELECT fname, lname FROM employee WHERE salary > 40000;
-- 2. Declare NOT FOUND handler
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
-- 3. Open the cursor
OPEN emp_cursor;
L: LOOP
-- 4. Fetch next tuple
FETCH emp_cursor INTO fname1, lname1;
-- Handler will set finished = 1 if cursor is empty
IF finished = 1 THEN
LEAVE L;
END IF;
-- build emp list
SET nameList = CONCAT( nameList, fname1, ' ', lname1, ';' );
END LOOP ;
-- 5. Close cursor when done
CLOSE emp_cursor;
SELECT nameList ;
END //
DELIMITER
Eg2.
DROP PROCEDURE IF EXISTS depreciation_calculator;
# depreciation calculator..........................................
CREATE PROCEDURE depreciation_calculator(IN deprcesionDate INT)
BEGIN
DECLARE acc DOUBLE;
DECLARE diff INT;
DECLARE currentDate DATE;
DECLARE depDate VARCHAR(12);
DECLARE dep DOUBLE;
DECLARE bookValue DOUBLE;
DECLARE assetId INT;
DECLARE depStatus VARCHAR(12);
DECLARE finished INTEGER DEFAULT 0;
DECLARE emp_cursor CURSOR FOR SELECT
dep_date,
dep_amount,
dep_status,
asset_ass_id,
book_value,
accumulative_value
FROM depreciation;
-- 2. Declare NOT FOUND handler
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
-- 3. Open the cursor
OPEN emp_cursor;
L: LOOP
-- 4. Fetch next element
FETCH emp_cursor
INTO depDate, dep, depStatus, assetId, bookValue, acc;
-- Handler will set finished = 1 if cursor is empty
IF finished = 1
THEN
LEAVE L;
END IF;
SET currentDate = DATE(now());
SET diff := TIMESTAMPDIFF(MONTH, depDate, currentDate);
IF diff > 12 && diff <= 13 && bookValue > 0
THEN
SET depDate = currentDate;
SET dep = dep;
SET acc = acc + dep;
SET bookValue = bookValue - dep;
IF bookValue = 0
THEN
SET depStatus = 'depreciated';
END IF;
INSERT INTO depreciation (dep_date, dep_amount, dep_status, dep_description, dep_commnet, asset_ass_id, book_value, accumulative_value)
VALUES (depDate, dep, depStatus, 1, 1, assetId, bookValue, acc);
END IF;
END LOOP;
-- 5. Close cursor when done
CLOSE emp_cursor;
SELECT diff;
END;
I want get the value from Exec(#sql) and assign to #Rowcount(int)
Here is my query:
'SET #RowCount = (select count(*)
FROM dbo.Comm_Services
WHERE CompanyId = '+cast(#CompanyId as char)+' and '+#condition+')'
On the one hand you could use sp_executesql:
exec sp_executesql N'select #rowcount=count(*) from anytable',
N'#rowcount int output', #rowcount output;
On the other hand you could use a temporary table:
declare #result table ([rowcount] int);
insert into #result ([rowcount])
exec (N'select count(*) from anytable');
declare #rowcount int = (select top (1) [rowcount] from #result);
DECLARE #nReturn int = 0
EXEC #nReturn = Stored Procedure
Was playing with this today... I believe you can also use ##ROWCOUNT, like this:
DECLARE #SQL VARCHAR(50)
DECLARE #Rowcount INT
SET #SQL = 'SELECT 1 UNION SELECT 2'
EXEC(#SQL)
SET #Rowcount = ##ROWCOUNT
SELECT #Rowcount
Then replace the SELECT 1 UNION SELECT 2 with your actual select without the count. I'd suggest just putting 1 in your select, like this:
SELECT 1
FROM dbo.Comm_Services
WHERE....
....
(as opposed to putting SELECT *)
Hope that helps.
that's my procedure
CREATE PROC sp_count
#CompanyId sysname,
#codition sysname
AS
SET NOCOUNT ON
CREATE TABLE #ctr
( NumRows int )
DECLARE #intCount int
, #vcSQL varchar(255)
SELECT #vcSQL = ' INSERT #ctr FROM dbo.Comm_Services
WHERE CompanyId = '+#CompanyId+' and '+#condition+')'
EXEC (#vcSQL)
IF ##ERROR = 0
BEGIN
SELECT #intCount = NumRows
FROM #ctr
DROP TABLE #ctr
RETURN #intCount
END
ELSE
BEGIN
DROP TABLE #ctr
RETURN -1
END
GO
If i understand you correctly, (i probably don't)
'SELECT #RowCount = COUNT(*)
FROM dbo.Comm_Services
WHERE CompanyId = ' + CAST(#CompanyId AS CHAR) + '
AND ' + #condition
Here's my scenario:
Let's say I have a stored procedure in which I need to call another stored procedure on a set of specific ids; is there a way to do this?
i.e. instead of needing to do this:
exec p_MyInnerProcedure 4
exec p_MyInnerProcedure 7
exec p_MyInnerProcedure 12
exec p_MyInnerProcedure 22
exec p_MyInnerProcedure 19
Doing something like this:
*magic where I specify my list contains 4,7,12,22,19*
DECLARE my_cursor CURSOR FAST_FORWARD FOR
*magic select*
OPEN my_cursor
FETCH NEXT FROM my_cursor INTO #MyId
WHILE ##FETCH_STATUS = 0
BEGIN
exec p_MyInnerProcedure #MyId
FETCH NEXT FROM my_cursor INTO #MyId
END
My Main goal here is simply maintainability (easy to remove/add id's as the business changes), being able to list out all Id's on a single line... Performance shouldn't be as big of an issue
declare #ids table(idx int identity(1,1), id int)
insert into #ids (id)
select 4 union
select 7 union
select 12 union
select 22 union
select 19
declare #i int
declare #cnt int
select #i = min(idx) - 1, #cnt = max(idx) from #ids
while #i < #cnt
begin
select #i = #i + 1
declare #id = select id from #ids where idx = #i
exec p_MyInnerProcedure #id
end
What I do in this scenario is create a table variable to hold the Ids.
Declare #Ids Table (id integer primary Key not null)
Insert #Ids(id) values (4),(7),(12),(22),(19)
-- (or call another table valued function to generate this table)
Then loop based on the rows in this table
Declare #Id Integer
While exists (Select * From #Ids)
Begin
Select #Id = Min(id) from #Ids
exec p_MyInnerProcedure #Id
Delete from #Ids Where id = #Id
End
or...
Declare #Id Integer = 0 -- assuming all Ids are > 0
While exists (Select * From #Ids
where id > #Id)
Begin
Select #Id = Min(id)
from #Ids Where id > #Id
exec p_MyInnerProcedure #Id
End
Either of above approaches is much faster than a cursor (declared against regular User Table(s)). Table-valued variables have a bad rep because when used improperly, (for very wide tables with large number of rows) they are not performant. But if you are using them only to hold a key value or a 4 byte integer, with a index (as in this case) they are extremely fast.
use a static cursor variable and a split function:
declare #comma_delimited_list varchar(4000)
set #comma_delimited_list = '4,7,12,22,19'
declare #cursor cursor
set #cursor = cursor static for
select convert(int, Value) as Id from dbo.Split(#comma_delimited_list) a
declare #id int
open #cursor
while 1=1 begin
fetch next from #cursor into #id
if ##fetch_status <> 0 break
....do something....
end
-- not strictly necessary w/ cursor variables since they will go out of scope like a normal var
close #cursor
deallocate #cursor
Cursors have a bad rep since the default options when declared against user tables can generate a lot of overhead.
But in this case the overhead is quite minimal, less than any other methods here. STATIC tells SQL Server to materialize the results in tempdb and then iterate over that. For small lists like this, it's the optimal solution.
You can try as below :
declare #list varchar(MAX), #i int
select #i=0, #list ='4,7,12,22,19,'
while( #i < LEN(#list))
begin
declare #item varchar(MAX)
SELECT #item = SUBSTRING(#list, #i,CHARINDEX(',',#list,#i)-#i)
select #item
--do your stuff here with #item
exec p_MyInnerProcedure #item
set #i = CHARINDEX(',',#list,#i)+1
if(#i = 0) set #i = LEN(#list)
end
I usually use the following approach
DECLARE #calls TABLE (
id INT IDENTITY(1,1)
,parameter INT
)
INSERT INTO #calls
select parameter from some_table where some_condition -- here you populate your parameters
declare #i int
declare #n int
declare #myId int
select #i = min(id), #n = max(id) from #calls
while #i <= #n
begin
select
#myId = parameter
from
#calls
where id = #i
EXECUTE p_MyInnerProcedure #myId
set #i = #i+1
end
CREATE TABLE #ListOfIDs (IDValue INT)
DECLARE #IDs VARCHAR(50), #ID VARCHAR(5)
SET #IDs = #OriginalListOfIDs + ','
WHILE LEN(#IDs) > 1
BEGIN
SET #ID = SUBSTRING(#IDs, 0, CHARINDEX(',', #IDs));
INSERT INTO #ListOfIDs (IDValue) VALUES(#ID);
SET #IDs = REPLACE(',' + #IDs, ',' + #ID + ',', '')
END
SELECT *
FROM #ListOfIDs
Make a connection to your DB using a procedural programming language (here Python), and do the loop there. This way you can do complicated loops as well.
# make a connection to your db
import pyodbc
conn = pyodbc.connect('''
Driver={ODBC Driver 13 for SQL Server};
Server=serverName;
Database=DBname;
UID=userName;
PWD=password;
''')
cursor = conn.cursor()
# run sql code
for id in [4, 7, 12, 22, 19]:
cursor.execute('''
exec p_MyInnerProcedure {}
'''.format(id))