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

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.

Related

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 :)

DB2 Stored Procedures- looping through values?

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

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.

How to re-use a SQL query in a PL/SQL procedure?

I am writing a PL/SQL procedure. In the body of this procedure, how can I use twice the same query without re-writing it ?
To simplify, let's say that I have this SQL query :
SELECT *
FROM mytable
WHERE age > 18
Is there a way to "store it", so I could do for example :
SELECT COUNT(*) INTO var1
FROM myQuery
I know the WITH ... AS keywords, but as I know it can be only used in the current statement, and I want to be able to call it from different statements.
Thanks !
There are various possibilities. Here are the ones I think of immediately, there are probably others:
Declare an explicit CURSOR using your query, and use that cursor multiple times in the body of your procedure.
Store the query in a string variable, and use EXECUTE IMMEDIATE to run it multiple times
Execute the query once, storing the results in a local collection (nested table, most likely), and process those stored results multiple times
Create a function that executes the query and returns its results as a nested-table type. Then SELECT FROM TABLE( my_function ) multiple times

SQL stored procedure combine result

I have written two SQL Server stored procedures
For example:
create PROCEDURE query1
AS
SQL code here...
create PROCEDURE query2
AS
SQL code here...
Now I can call them individually using the following command, and the returned value is the following.
exec query1
Study availability
ACR 99.97%
Now I want to combine these stored procedures and get the results in one shot, like :
exec query1
exec query2
and it give result something like following but somehow its now working its giving me syntax error. How do I combine two stored procedures and get results in one report?
This is T-SQL query
Study availability
ACR 99.97%
FOS 87.88%
You can't call them the way you describe (ie exec query1 exec query2). Here is one alternative assuming each proc returns a single value:
declare #result as table (
ACR float,
FOS float
)
INSERT INTO #result(ACR)
exec query1
INSERT INTO #result(FOS)
exec query2
SELECT ACR,FOS from #result
Since they both return the same column headings/data types I recommend combining the 2 separate queries into a single query and use UNION ALL.
EX:
SELECT 'ACR' AS Study,
SomeField AS Availability
FROM SomeTable1
UNION ALL
SELECT 'FOS' AS Study,
SomeField AS Availability
FROM SomeTable2;
It's hard to give more specific advice without seeing your actual Stored Procedures, but this is definitely much clearer than having 2 separate procedures. Hope this helps.
You can try that:
exec query1; exec query2
But be aware that the result is not combined, you just get the result of both SPs as separate result sets.
It depends on your code, you can insert the results of each SP into a table, and then UNION them together to get the single result set you are looking for - but this often can be slower if it's a lot of rows since you are making copies of the results instead of just streaming them out to the client. And it breaks the ability of the optimizer to combine things across the boundary, since it has to write them to the temporary tables.
If the procs aren't complex, I would consider making them into views or inline table-valued functions. These can be easily combined by other routines like views, functions or procedures and make things a bit more modular.