DB2 Stored Procedures- looping through values? - sql

Okay, so I'm a novice at writing stored procedures. I'm trying to perform a function similar to a foreach() you would see in a programming language. Right now I have a temp table populated with the values I'd like to loop through. I would like to (for each value in this table) execute a SQL statement based upon that value. So, here's my pseudocode to illustrate what I'm really after here:
foreach(value in my temp table) {
SELECT * FROM TABLE WHERE column_x = value
}
No I know nothing of stored procedures so how can I get this done? Here's my script so far:
DROP TABLE SESSION.X;
CREATE GLOBAL TEMPORARY TABLE
SESSION.X (
TD_NAME CHAR(30)
);
INSERT INTO
SESSION.X
SELECT DISTINCT
TD_NAME
FROM
DBA.AFFIN_PROG_REPORT
WHERE
TD_NAME IS NOT NULL;
Any help is very much appreciated!

You need, by example, a cursor.
See the example: https://stackoverflow.com/a/4975012/3428749
See the documentation: https://msdn.microsoft.com/pt-br/library/ms180169(v=sql.120).aspx

Related

Why is it quicker to use a temporary table when inserting data from a user function into a table variable?

I have an inline table-valued function. I want to insert the output of that function into a table variable so I can pass it to another function.
DECLARE #PeopleToEmail mb.PeopleToEmailOrPhone;
INSERT INTO
#PeopleToEmail
SELECT
*
FROM
mb.GetOptedInEmails('All')
;
On my dataset, this query takes 28 seconds to run.
However, if I use an intermediary temporary table, runtime drops to around 9 seconds.
SELECT
*
INTO
#OptIns
FROM
mb.GetOptedInEmails('All')
;
DECLARE #PeopleToEmail mb.PeopleToEmailOrPhone;
INSERT INTO
#PeopleToEmail
SELECT
*
FROM
#OptIns
This makes no sense to me and means my code is twice as long as it needs to be. Can anyone help me
Understand why this is happening.
Think of another way of optimising the query without the intermediary table.
I'm stuck on SQL Server 2012. The function is quite long but you can view it here.
No Temp Table
Temp Table

INSERT FROM EXISTING SELECT without amending

With GDPR in the UK on the looming horizon and already have a team of 15 users creating spurious SELECT statements (in excess of 2,000) across 15 differing databases I need to be able to create a method to capture an already created SELECT statement and be able to assign surrogate keys/data WITHOUT rewriting every procedure we already have.
There will be a need to run the original team members script as normal and there will be requirements to pseudo the values.
My current thinking is to create a stored procedure along the lines of:
CREATE PROC Pseudo (#query NVARCHAR(MAX))
INSERT INTO #TEMP FROM #query
Do something with the data via a mapping table of real and surrogate/pseudo data.
UPDATE #TEMP
SET FNAME = (SELECT Pseudo_FNAME FROM PseudoTable PT WHERE #TEMP.FNAME = PT.FNAME)
SELECT * FROM #TEMP
So that team members can run their normal SELECT statements and get pseudo data simply by using:
EXEC Pseudo (SELECT FNAME FROM CUSTOMERS)
The problem I'm having is you can't use:
INSERT INTO #TEMP FROM #query
So I tried via CTE:
WITH TEMP AS (#query)
..but I can't use that either.
Surely there's a way of capturing the recordset from an existing select that I can pull into a table to amend it or capture the SELECT statement; without having to amend the original script. Please bear in mind that each SELECT statement will be unique so I can't write COLUMN or VALUES etc.
Does any anyone have any ideas or a working example(s) on how to best tackle this?
There are other lengthy methods I could externally do to carry this out but I'm trying to resolve this within SQL if possible.
So after a bit of deliberation I resolved it.
I passed the Original SELECT SQL to SP that used some SQL Injection, which when executed INSERTed data. I then Updated from that dataset.
The end result was "EXEC Pseudo(' Orginal SQL ;')
I will have to set some basic rules around certain columns for now as a short term fix..but at least users can create NonPseudo and Pseudo data as required without masses of reworking :)

Calling stored procedure to insert multiple values

In our application we have a multiline grids which have many records. For inserting or updating we are calling a stored procedure.
As per the current implementation the stored procedure is calling for each line in the grid. For each line it checks the existence in the table. If data is already there, it will update the table else insert new data into the table.
Instead of calling the procedure for each line, we thought create a table value parameter and pass all the grid values at the same time.
My questions are:
Is it a good approach?
How to handle the existence check (for insert or update) if I pass the values as table-valued parameter? Do I need to loop through the table and check it?
Is it better to have separate stored procedures for insert and update?
Please provide your suggestions. Thanks in advance.
1) TVP is a good approach. And a single stored proc call is more efficient with fewer calls to the Database.
2) You haven't made it clear if each row in the grid has some kind of ID column that determines if the data exists in the Table, however assuming there is, make sure that it is indexed then use INSERT INTO and UPDATE statements like this:
To add new rows:
INSERT INTO [grid_table]
SELECT * FROM [table_valued_parameter]
WHERE [id_column] NOT IN (SELECT [id_column] FROM [grid_table])
To update existing rows:
UPDATE gt
SET gt.col_A = tvp.col_A,
gt.col_B = tvp.col_B,
gt.col_C = tvp.col_C,
...
gt.col_Z = tvp.col_Z
FROM [grid_table] gt
INNER JOIN [table_valued_parameter] tvp ON gt.id_column = tvp.id_column
NB:
No need to do an IF EXISTS() or anything as the WHERE and JOIN
clauses will run the same checks,so no need to do a 'pre-check'
before running each statement.
This assumes the TVP data isthe same structure as the Table in the
database.
YOU MUST make sure the id_column is indexed.
I've use 'INNER JOIN' instead of just 'JOIN' to make the point it is an inner join
3) Using the approach above you just new one stored proc, simple and effective
It's a good approach
Any way try to put the logic through object level for iterating and checking and finally insert/update in T-SQL. This reduces overhead for RDMS as object level functionality is faster than operations in RDBMS.
Dont put too may stored procedures for each type of operation have a minimised procedures with multiple operations based on parameters you send to it.
Hope it helps!
Yes, it is a good approach. Calling procedure for each row is bad for performance. TVPs make life easier.
Yes, you can do that check in stored procedure, which should be a simple SELECT on uniqueId in most of the cases.
With this approach, yes, it is better to have both in same stored procedure.
1) Using TVP is good approach, but send only new or updated rows as TVP, no need to send entire datagrid.
2) For INSERT/UPDATE use MERGE example:
MERGE [dbo].[Contact] AS [Target]
USING #Contact AS [Source] ON [Target].[Email] = [Source].[Email]
WHEN MATCHED THEN
UPDATE SET [FirstName] = [Source].[FirstName],
[LastName] = [Source].[LastName]
WHEN NOT MATCHED THEN
INSERT ( [Email], [FirstName], [LastName] )
VALUES ( [Source].[Email], [Source].[FirstName], [Source].[LastName] );
3) For your case one stored procedure is enough.

Deleting a temp table based on a string value?

Is there a way in sql server 2008 to delete #tt using a string:
delete temp table with name = 'tt'
edit: what would really be nice if there was a function like: getString(#tt) that returned 'tt'
You could do this with dynamic SQL:
EXEC('DROP TABLE #' + #MyTempTable)
If you go this route I would give this article a good read to get an understanding of the pros and cons of dynamic sql.
Although you can do this with dynamic SQL, I'm not sure how you are going to create varying temp tables in a parent session scope with non-dynamic SQL and then use dynamic SQL within a child session scope.
Can you give an example of what you are doing to create the tables and where you want them to be dropped?

How to SELECT [temp table1] = [subselect 1], [temp table2] = [subselect 2] FROM [Stored Procedure]

I have a stored procedure that returns two selects, which I use in a report.
The first select is data to display in tabular format and the second are metadata to display in the report head, like showed below:
CREATE PROCEDURE dbo. GetReport
#Input INT
AS
BEGIN
--Get #Metadata
-- #Results = f(#Metadata) … compex calculation
SELECT * FROM #Results
SELECT * FROM #Metadata
END
As the sproc calculation is quite intensive, I would like to prepare the report lines as plain data (in two tables: PrecalcResults and PrecalcMetadata) for some mostly used sproc parameters overnight.
Lather I would directly select the precalculated vaues or calculate them with the sproc according to the parameters.
For maintenance reasons I would like to use the same sproc to calculate data that would be:
1. showed in the report
2. be stored in PrecalcResults and PrecalcMetadata (with the used parameters)
If I would have single select sproc I would an approach desctibed here:
Insert results of a stored procedure into a temporary table
As I have multiselect sproc I would like to do something like above but with two tables.
In .net I would do DataSet.Tables[0] and DataSet.Tables[1]..., but I want to do it in tsql, to run it in daily job.
Is this even possible in MS SQL?
I have to apologize myself, from the answer below I can see I was not very clear.
I would like to do implement this functionality as pure TSQL.
Yes, this is possible.
It's perfectly fine to return multiple result sets from a single stored procedure as you have suggested.
Your only potential issue is the limitation of a TableAdapter being able to pull both result sets from the stored procedure, but there's a very simple work-around for that issue.