Iterate through sql script using different values - sql

Here is part of my script:
DECLARE #dataId int = 123
-- Here I run more SQL scripts using #dataId
Select from table A where id = #dataId
-- So on it goes in other tables and delete and update other tables
My question is there a way I can enter 100 values in #dataId and it will iterate through the script in an order? Is there a simpler way to do this in SQL Server 2008 rather then manually entering #dataId each time?

Well, according to your comment, then I guess that CURSORS are the way to go. Something like this should do:
DECLARE #dataId int
DECLARE DataIds CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY FOR
SELECT DataId
FROM YourTableWithDataIdsHere
OPEN DataIds
FETCH NEXT FROM DataIds INTO #dataId
WHILE ##FETCH_STATUS = 0
BEGIN
-- Here I run more SQL scripts using #dataId
Select from table A where id = #dataId
-- So on it goes in other tables and delete and update other tables
FETCH NEXT FROM DataIds INTO #dataId
END
CLOSE DataIds
DEALLOCATE DataIds

Related

How to run the same parameter to 22 similar databases?

I have been pulling data from a single database that stores the data for 22 facilities together. The database has now been redesigned and there are 22 separate databases (similar) for each of the facilities that we have. How can use the same code and run it against all these databases at the same time? Like, how can I pass the same parameter and pull data from all 22 databases?
You can use CURSOR to achieve your requirement. Here I placed a sample Dynamic Insert Script which you can adjust as per your requirement. One manual task is you have to insert one by one 22 database name using script in a temporary table. The facility is that is is a one time work and you can re use the script when ever it is required.
--The first step will be creating a Table variable
--where you will INSERT all your database names
--for a further loop as below-
DECLARE #DbName VARCHAR(200)
DECLARE #DatabaseList TABLE (DbName VARCHAR(200))
INSERT INTO #DatabaseList (DbName) VALUES('db_name_1')
INSERT INTO #DatabaseList (DbName) VALUES('db_name_2')
--.......................
INSERT INTO #DatabaseList (DbName) VALUES('db_name_22')
--Now you can use CURSOR to generate the loop
--and execute your required script as shown below
DECLARE db_cursor CURSOR FOR
SELECT DbName FROM #DatabaseList
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #DbName
WHILE ##FETCH_STATUS = 0
BEGIN
--HERE You need to write your script That you
--Execute for all your database. I have added
--a sample script for your reference only
-- You can see the Database Name inserted in the Script Dynamically from the Loop.
--The script could be INSERT/Update/DELETE As per requirement
EXEC
(
'INSERT INTO '+#DbName+'.dbo.<Your_table_Name_Here>
SELECT * FROM master.dbo.<Your_table_Name_Here> '
)
--END OF Dynamic Part
FETCH NEXT FROM db_cursor INTO #DbName
END
CLOSE db_cursor
DEALLOCATE db_cursor

How to execute single sql query in multiple databases

I have cloud server where I've hosted a web application for my customers. Each customer has a different SQL database and website in IIS. Whenever I want to execute a sql query to update something, I have to do this manually in each database. There are almost 50 databases and it takes around an hour in executing single query each time. Can someone provide me a tool or way by which I just select all the database at once and execute that query simply?
If I guess you have all databases are in same structure and every time you run script to update something, the script basically same and you just run that same script one by one for each customer.
If the above case is true, you can use CURSOR to produce a Loop between your all databases and Execute necessary script to serve your purpose.
Note: This is not the solution, Just Idea.
--The first step will be creating a Table variable
--where you will INSERT all your database names
--for a further loop as below-
DECLARE #DbName VARCHAR(200)
DECLARE #DatabaseList TABLE (DbName VARCHAR(200))
INSERT INTO #DatabaseList (DbName) VALUES('db_name_1')
INSERT INTO #DatabaseList (DbName) VALUES('db_name_2')
--.......................
INSERT INTO #DatabaseList (DbName) VALUES('db_name_50')
--Now you can use CURSOR to generate the loop
--and execute your required script as shown below
DECLARE db_cursor CURSOR FOR
SELECT DbName FROM #DatabaseList
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #DbName
WHILE ##FETCH_STATUS = 0
BEGIN
--HERE You need to write your script That you
--Execute for all your database. I have added
--a sample script where I guess you updating
--certain tables in your all database WHERE ID = 1
-- You can see the Database Name inserted in the
-- Script Dynamically from the Loop
EXEC ('UPDATE '+#DbName+'.dbo.<Your_table_Name_Here>
WHERE ID=1')
--END OF Dynamic Part
FETCH NEXT FROM db_cursor INTO #DbName
END
CLOSE db_cursor
DEALLOCATE db_cursor

SQL LOOP Pass values from Temp Table as parameters to stored procedure

Using SQL Server 2016, I have a huge query for our Finance Dept that uses #Year and #FinPeriod to match up transactions with a period. And for reporting we normally pass a single value into the stored procedure. But now we are required to populate the underlying tables with the data that would normally be generated on the fly.
Is there a loop anyone can help with please? I have a temp table with year values column and a finperiod for each of those years. I am looking to loop through this table - passing in both year and period to the stored procedure, one after the other until they have all been ran.
The stored procedure element is fine for me, just getting the loop/passing part to work would be a help.
So far I have:
declare #fiscalyearid numeric(9)
declare #FiscalYear numeric(9)
declare #FiscalMonthOfYear numeric(9)
declare #Year numeric(9)
declare #FinPeriod numeric(9)
if object_id('tempdb..#dateloop','u') is not null
drop table #dateloop
select distinct
identity(int,1,1) as ID,
FiscalYear_int, FiscalMonthOfYear
into
#dateloop
from
[DW].[DDS].[dimDate]
where
FiscalYear_int = '2018'
DECLARE C CURSOR LOCAL FAST_FORWARD FOR --
SELECT
ID, FiscalYear_int, FiscalMonthOfYear
FROM
#dateloop;
OPEN C;
FETCH C INTO #FiscalYear, #FiscalMonthOfYear;
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC [dbo].[Origen_Reporting->SSRS_Capex_Monitoring_Report_Expenditure] #Year, #FinPeriod
FETCH C INTO #Year,#FinPeriod
END
CLOSE C;
DEALLOCATE C;
Any tips would be brilliant. Thank you
I guess you want your Cursor logic to work. Below is the code you can use to loop through your dates and call proc in loop.
DECLARE C CURSOR LOCAL FAST_FORWARD FOR --
SELECT
FiscalYear_int, FiscalMonthOfYear
FROM
#dateloop;
OPEN C;
Fetch next from c into #FiscalYear, #FiscalMonthOfYear
WHILE ##FETCH_STATUS = 0
BEGIN
select #FiscalYear, #FiscalMonthOfYear --exec proc passing these values
EXEC [dbo].[Origen_Reporting->SSRS_Capex_Monitoring_Report_Expenditure] #FiscalYear, #FiscalMonthOfYear
FETCH next from c INTO #FiscalYear,#FiscalMonthOfYear
END
CLOSE C;
DEALLOCATE C;

Fetch SQL Server stored procedure output results into table

I have tried some solutions from the internet but they are not working for me .
My task is to get the out put of stored procedure into a table.The data is being inserted inside a cursor by loop . I am creating temporary table to store and display the data.
My code:
ALTER procedure [dbo].[usp_Test]
AS
SET NOCOUNT ON;
declare #caseId int;
declare #CHG_ID int;
declare #HEAR_ID int;
SET #CHG_ID = 1
set #testid = 1;
DECLARE db_cursor CURSOR FOR
SELECT C_CASE_ID
FROM table1 // tHERE WILL BE MULTIPLE CASEIDS
-- here I am trying to delete the temporary table, but it does not work
IF OBJECT_ID('tempdb..##test_temp_table') IS NOT NULL
TRUNCATE TABLE ##test_temp_table
ELSE
CREATE TABLE test_temp_table(HEAR_ID int)
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #caseId
WHILE ##FETCH_STATUS = 0
BEGIN
insert into test_temp_table
EXEC STOREDPROCTEST2 #caseId, 1, #HEAR_ID OUTPUT;
-- LOOP THROUGH THE CURSOR TO GET ALL CASE IDS
FETCH NEXT FROM db_cursor INTO #caseId
SELECT HEAR_ID FROM test_temp_table;
END
CLOSE db_cursor
DEALLOCATE db_cursor;
I have two issues:
I cannot delete the temporary table
I am not seeing any output from the temporary table
[##test_temp_table] and [test_temp_table] are two different tables. First one is a global temp table, second one is a user table. I believe you want to replace the user table with the global temp table, i.e. replace object [test_temp_table] with [##test_temp_table]. or vice versa. In the end, you have to ensure you are querying the correct table.

How do I execute a stored procedure once for each row returned by query?

I have a stored procedure that alters user data in a certain way. I pass it user_id and it does it's thing. I want to run a query on a table and then for each user_id I find run the stored procedure once on that user_id
How would I write query for this?
use a cursor
ADDENDUM: [MS SQL cursor example]
declare #field1 int
declare #field2 int
declare cur CURSOR LOCAL for
select field1, field2 from sometable where someotherfield is null
open cur
fetch next from cur into #field1, #field2
while ##FETCH_STATUS = 0 BEGIN
--execute your sproc on each row
exec uspYourSproc #field1, #field2
fetch next from cur into #field1, #field2
END
close cur
deallocate cur
in MS SQL, here's an example article
note that cursors are slower than set-based operations, but faster than manual while-loops; more details in this SO question
ADDENDUM 2: if you will be processing more than just a few records, pull them into a temp table first and run the cursor over the temp table; this will prevent SQL from escalating into table-locks and speed up operation
ADDENDUM 3: and of course, if you can inline whatever your stored procedure is doing to each user ID and run the whole thing as a single SQL update statement, that would be optimal
try to change your method if you need to loop!
within the parent stored procedure, create a #temp table that contains the data that you need to process. Call the child stored procedure, the #temp table will be visible and you can process it, hopefully working with the entire set of data and without a cursor or loop.
this really depends on what this child stored procedure is doing. If you are UPDATE-ing, you can "update from" joining in the #temp table and do all the work in one statement without a loop. The same can be done for INSERT and DELETEs. If you need to do multiple updates with IFs you can convert those to multiple UPDATE FROM with the #temp table and use CASE statements or WHERE conditions.
When working in a database try to lose the mindset of looping, it is a real performance drain, will cause locking/blocking and slow down the processing. If you loop everywhere, your system will not scale very well, and will be very hard to speed up when users start complaining about slow refreshes.
Post the content of this procedure you want call in a loop, and I'll bet 9 out of 10 times, you could write it to work on a set of rows.
You can do it with a dynamic query.
declare #cadena varchar(max) = ''
select #cadena = #cadena + 'exec spAPI ' + ltrim(id) + ';'
from sysobjects;
exec(#cadena);
Something like this substitutions will be needed for your tables and field names.
Declare #TableUsers Table (User_ID, MyRowCount Int Identity(1,1)
Declare #i Int, #MaxI Int, #UserID nVarchar(50)
Insert into #TableUser
Select User_ID
From Users
Where (My Criteria)
Select #MaxI = ##RowCount, #i = 1
While #i <= #MaxI
Begin
Select #UserID = UserID from #TableUsers Where MyRowCount = #i
Exec prMyStoredProc #UserID
Select
#i = #i + 1, #UserID = null
End
Use a table variable or a temporary table.
As has been mentioned before, a cursor is a last resort. Mostly because it uses lots of resources, issues locks and might be a sign you're just not understanding how to use SQL properly.
Side note: I once came across a solution that used cursors to update
rows in a table. After some scrutiny, it turned out the whole thing
could be replaced with a single UPDATE command. However, in this case,
where a stored procedure should be executed, a single SQL-command
won't work.
Create a table variable like this (if you're working with lots of data or are short on memory, use a temporary table instead):
DECLARE #menus AS TABLE (
id INT IDENTITY(1,1),
parent NVARCHAR(128),
child NVARCHAR(128));
The id is important.
Replace parent and child with some good data, e.g. relevant identifiers or the whole set of data to be operated on.
Insert data in the table, e.g.:
INSERT INTO #menus (parent, child)
VALUES ('Some name', 'Child name');
...
INSERT INTO #menus (parent,child)
VALUES ('Some other name', 'Some other child name');
Declare some variables:
DECLARE #id INT = 1;
DECLARE #parentName NVARCHAR(128);
DECLARE #childName NVARCHAR(128);
And finally, create a while loop over the data in the table:
WHILE #id IS NOT NULL
BEGIN
SELECT #parentName = parent,
#childName = child
FROM #menus WHERE id = #id;
EXEC myProcedure #parent=#parentName, #child=#childName;
SELECT #id = MIN(id) FROM #menus WHERE id > #id;
END
The first select fetches data from the temporary table. The second select updates the #id. MIN returns null if no rows were selected.
An alternative approach is to loop while the table has rows, SELECT TOP 1 and remove the selected row from the temp table:
WHILE EXISTS(SELECT 1 FROM #menuIDs)
BEGIN
SELECT TOP 1 #menuID = menuID FROM #menuIDs;
EXEC myProcedure #menuID=#menuID;
DELETE FROM #menuIDs WHERE menuID = #menuID;
END;
Can this not be done with a user-defined function to replicate whatever your stored procedure is doing?
SELECT udfMyFunction(user_id), someOtherField, etc FROM MyTable WHERE WhateverCondition
where udfMyFunction is a function you make that takes in the user ID and does whatever you need to do with it.
See http://www.sqlteam.com/article/user-defined-functions for a bit more background
I agree that cursors really ought to be avoided where possible. And it usually is possible!
(of course, my answer presupposes that you're only interested in getting the output from the SP and that you're not changing the actual data. I find "alters user data in a certain way" a little ambiguous from the original question, so thought I'd offer this as a possible solution. Utterly depends on what you're doing!)
I like the dynamic query way of Dave Rincon as it does not use cursors and is small and easy. Thank you Dave for sharing.
But for my needs on Azure SQL and with a "distinct" in the query, i had to modify the code like this:
Declare #SQL nvarchar(max);
-- Set SQL Variable
-- Prepare exec command for each distinctive tenantid found in Machines
SELECT #SQL = (Select distinct 'exec dbo.sp_S2_Laser_to_cache ' +
convert(varchar(8),tenantid) + ';'
from Dim_Machine
where iscurrent = 1
FOR XML PATH(''))
--for debugging print the sql
print #SQL;
--execute the generated sql script
exec sp_executesql #SQL;
I hope this helps someone...