SELECT FROM stored procedure? - sql

If I have a stored proc in SQL Server 2008, I know I can run it from management studio like so:
exec rpt_myproc #include_all = 1, #start_date = '1/1/2010'
But I'm using an ad-hoc query tool that wasn't returning any results. So I asked it to give me the SQL it was running and it returns this:
SELECT DISTINCT TOP 100000
[dbo].[rpt_myproc].[company_name] AS 'company name',
[dbo].[rpt_myproc].[order_number] AS 'order number]
FROM [dbo].[rpt_myproc]
WHERE
([dbo].[rpt_myproc].[PARAM_start_date] IN ('1/1/2010'))
AND ([dbo].[rpt_myproc].[PARAM_include_all] IN ('1'))
I'm not familiar with that syntax. Is that even possible? The ad-hoc tool isn't failing, but it may be swallowing that error. Then again, maybe it's just giving me a shorthand which it will use translate to the proper syntax later. But if so, why would it give it to me in this form?
I can't seem to get that SQL to execute in Management Studio, so I was wondering if something like that were possible?

I understand that this is more than 3 years old, but in case anybody else is looking for an answer to this question. I had to deal with this reporting platform, Izenda, and have found that stored procedures are treated differently than the output from the "sql" icon. Here is what happens when you select sp as data source
A dynamic sql is build
It creates a two temporary tables with all of the columns that your sp is returning
The first temp table is populated with the result from your stored procedure
The second temp table is populated with the result plus the value of your input parameter.
A statement is created that queries these two temporary tables
Please note that if you don't feed it a parameter it will execute with a default value of empty string '' which will most likely return no data.
In my opinion, horrible idea to handle stored procs which is a good reason why we are planning to drop them for some other reporting solution.

You can insert the first result set of a stored procedure into a temporary table:
SELECT *
INTO #YourProc
FROM OPENROWSET('SQLNCLI',
'server=SERVERNAME\INSTANCENAME;trusted_connection=yes',
'set fmtonly off; exec rpt_myproc')
There's like 3 ways to do this, see this blog post. If you know the output beforehand, you can do it without the remote query.

What tool are you using? You should be able to specify the query type (i.e. SQL, or stored proc, etc)
Haven't used that tool before but a quick google came up with this example (not sure if it will help you)
Using a stored procedure in 5.x
This example uses a stored procedure to populate a table before report design or execution. As shown in the comments, the table StoredProcResults must already exist. Every time a report is created or viewed this stored procedure will update the results of the StoredProcResults table. For 6.x follow these instructions but treat the SP as a regular datasource.
// Customize a report on the fly prior to execution on a per user basis
public override void PreExecuteReportSet(Izenda.AdHoc.ReportSet reportSet){
/*this sample uses the adventure works database Here is the definition of the table and stored procedure created for this report.
CREATE TABLE [dbo].[StoredProcResults](
[ProductID] [int] NOT NULL,
[OrderQuantity] [int] NOT NULL,
[Total] [int] NOT NULL,
[DueDate] [smalldatetime] NOT NULL
) ON [PRIMARY]
CREATE PROCEDURE DoCustomAction (
#date1 as smalldatetime,
#date2 as smalldatetime
) AS
BEGIN
insert into StoredProcResults
select ProductID,OrderQty,LineTotal,ModifiedDate
from Sales.SalesOrderDetail
where ModifiedDate >= #date1 and ModifiedDate <= #date2
END
*/
string currentReportName = HttpContext.Current.Request.QueryString["rn"];
if (currentReportName == "StoredProcExample") {
SqlConnection myConnection = new SqlConnection(Izenda.AdHoc.AdHocSettings.SqlServerConnectionString);
SqlCommand myCommand = new SqlCommand("DoCustomAction", myConnection);
// Mark the Command as a SPROC
myCommand.CommandType = System.Data.CommandType.StoredProcedure;
// Add Parameters to SPROC
SqlParameter parameterdate1 = new SqlParameter("#date1", System.Data.SqlDbType.SmallDateTime);
parameterdate1.Value = "1/1/2003";
myCommand.Parameters.Add(parameterdate1);
SqlParameter parameterdate2 = new SqlParameter("#date2", System.Data.SqlDbType.SmallDateTime);
parameterdate2.Value = "12/31/2003";
myCommand.Parameters.Add(parameterdate2);
try{
myConnection.Open();
myCommand.ExecuteNonQuery();
}
finally{
myConnection.Close();
}
}
}

Are you sure it is a sproc? I've never heard or seen a usage of doing a direct select from a sproc.
What I have seen that works and functions exactly as your code seems to be working is table-valued functions, which are functions, that can take parameters and return a "SELECT FROMable" table just like this (in essence giving you a 'parameterized' view).

Related

Using results of one stored procedure in another stored procedure - SQL Server

Is there any way to use the results of one stored procedure in another stored procedure without using a table variable or temp table? The logic is as follows:
IF (#example = 1)
BEGIN
DECLARE #temp TABLE (Id INT);
INSERT INTO #temp
EXEC [Procedure1] #ItemId = #StockId
set #Cost = (select top 1 id from #temp)
Ideally i would like to know if there is a way to do this without having to use a temp table. Looked around online but can't find anything that works. Any advice would be great.
In general, if you want to use user-defined code in a SELECT, then it is better to phrase the code as a user-defined function rather than a user-defined procedure.
That is, procedures should be used for their side effects and functions should be used for their return values.
That said, you can use openquery (documented here) to run an exec on a linked server. The linked server can be the server you are running on.

Getting result from SQL Server Stored Procedure

I need to get the result from a stored procedure in a MSSQL Server database. I tried different ways:
Using a Table Input Step, with this query: exec dbo.storedproc #param1 = 5, #param2 = 12, #param3 = null, #param4 = null, #param5 = '2017/08/29', #param6 = 1. When I right click on it -> Show output fields, it shows me the output fields from the stored procedure, but I don't know how to get the results and dump them into another table.
Using the Call DB Procedure step. With this one, I set up the input parameters, and tried to pass them through a Generate Rows step. But, With this one I don't even get the output parameters.
Please help me figure out how to do this.
With regards,
As #Brian.D.Myers suggested, the best approach is execute the stored procedure in a Table input step, and connect it to a Table output step. That, alongside the fact that the stored procedure must be executed with the following syntax: exec stored_procedure_name [#param = value,]
Thanks a lot!

How to pass variable as a parameter in Execute SQL Task SSIS?

I have ssis package in that I'm taking values from flat file and insert it into table.
I have taken one Execute SQL Task in that creating one temptable
CREATE TABLE [tempdb].dbo.##temptable
(
date datetime,
companyname nvarchar(50),
price decimal(10,0),
PortfolioId int,
stype nvarchar(50)
)
Insert into [tempdb].dbo.##temptable (date,companyname,price,PortfolioId,stype)
SELECT date,companyname,price,PortfolioId,stype
FROM ProgressNAV
WHERE (Date = '2011-09-30') AND (PortfolioId = 5) AND (stype in ('Index'))
ORDER BY CompanyName
Now in above query I need to pass (Date = '2011-09-30') AND (PortfolioId = 5) AND (stype in ('Index'))
these 3 parameter using variable name I have created variables in package so that I become dynamic.
In your Execute SQL Task, make sure SQLSourceType is set to Direct Input, then your SQL Statement is the name of the stored proc, with questionmarks for each paramter of the proc, like so:
Click the parameter mapping in the left column and add each paramter from your stored proc and map it to your SSIS variable:
Now when this task runs it will pass the SSIS variables to the stored proc.
The EXCEL and OLED DB connection managers use the parameter names 0 and 1.
I was using a oledb connection and wasted couple of hours trying to figure out the reason why the query was not working or taking the parameters. the above explanation helped a lot
Thanks a lot.
Along with #PaulStock's answer, Depending on your connection type, your variable names and SQLStatement/SQLStatementSource Changes
https://learn.microsoft.com/en-us/sql/integration-services/control-flow/execute-sql-task
SELECT, INSERT, UPDATE, and DELETE commands frequently include WHERE clauses to specify filters that define the conditions each row in the source tables must meet to qualify for an SQL command. Parameters provide the filter values in the WHERE clauses.
You can use parameter markers to dynamically provide parameter values. The rules for which parameter markers and parameter names can be used in the SQL statement depend on the type of connection manager that the Execute SQL uses.
The following table lists examples of the SELECT command by connection manager type. The INSERT, UPDATE, and DELETE statements are similar. The examples use SELECT to return products from the Product table in AdventureWorks2012 that have a ProductID greater than and less than the values specified by two parameters.
EXCEL, ODBC, and OLEDB
SELECT* FROM Production.Product WHERE ProductId > ? AND ProductID < ?
ADO
SELECT * FROM Production.Product WHERE ProductId > ? AND ProductID < ?
ADO.NET
SELECT* FROM Production.Product WHERE ProductId > #parmMinProductID
AND ProductID < #parmMaxProductID
The examples would require parameters that have the following names:
The EXCEL and OLED DB connection managers use the parameter names 0 and 1. The ODBC connection type uses 1 and 2.
The ADO connection type could use any two parameter names, such as Param1 and Param2, but the parameters must be mapped by their ordinal position in the parameter list.
The ADO.NET connection type uses the parameter names #parmMinProductID and #parmMaxProductID.
A little late to the party, but this is how I did it for an insert:
DECLARE #ManagerID AS Varchar (25) = 'NA'
DECLARE #ManagerEmail AS Varchar (50) = 'NA'
Declare #RecordCount AS int = 0
SET #ManagerID = ?
SET #ManagerEmail = ?
SET #RecordCount = ?
INSERT INTO...

How do I paramaterise a T-SQL stored procedure that drops a table?

I'm after a simple stored procedure to drop tables. Here's my first attempt:
CREATE PROC bsp_susf_DeleteTable (#TableName char)
AS
IF EXISTS (SELECT name FROM sysobjects WHERE name = #TableName)
BEGIN
DROP TABLE #TableName
END
When I parse this in MS Query Analyser I get the following error:
Server: Msg 170, Level 15, State 1, Procedure bsp_susf_DeleteTable, Line 6
Line 6: Incorrect syntax near '#TableName'.
Which kind of makes sense because the normal SQL for a single table would be:
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'tbl_XYZ')
BEGIN
DROP TABLE tbl_XYZ
END
Note the first instance of tbl_XYZ (in the WHERE clause) has single quotes around it, while the second instance in the DROP statement does not. If I use a variable (#TableName) then I don't get to make this distinction.
So can a stored procedure be created to do this? Or do I have to copy the IF EXISTS ... everywhere?
You should be able to use dynamic sql:
declare #sql varchar(max)
if exists (select name from sysobjects where name = #TableName)
BEGIN
set #sql = 'drop table ' + #TableName
exec(#sql)
END
Hope this helps.
Update: Yes, you could make #sql smaller, this was just a quick example. Also note other comments about SQL Injection Attacks
Personally I would be very wary of doing this. If you feel you need it for administrative purposes, please make sure the rights to execute this are extremely limited. Further, I would have the proc copy the table name and the date and the user executing it to a logging table. That way at least you will know who dropped the wrong table. You may want other protections as well. For instance you may want to specify certain tables that cannot be dropped ever using this proc.
Further this will not work on all tables in all cases. You cannot drop a table that has a foreign key associated with it.
Under no circumstances would I allow a user or anyone not the database admin to execute this proc. If you havea a system design where users can drop tables, there is most likely something drastically wrong with your design and it should be rethought.
Also, do not use this proc unless you have a really, really good backup schedule in place and experience restoring from backups.
You'll have to use EXEC to execute that query as a string. In other words, when you pass in the table name, define a varchar and assign the query and tablename, then exec the variable you created.
Edit: HOWEVER, I don't recommend that because someone could pass in sql rather than a TableName and cause all kinds of wonderful problems. See Sql injection for more information.
Your best bet is to create a parameterized query on the client side for this. For example, in C# I would do something like:
// EDIT 2: on second thought, ignore this code; it probably won't work
SqlCommand sc = new SqlCommand();
sc.Connection = someConnection;
sc.CommandType = Command.Text;
sc.CommandText = "drop table #tablename";
sc.Parameters.AddWithValue("#tablename", "the_table_name");
sc.ExecuteNonQuery();

Query times out in .Net SqlCommand.ExecuteNonQuery, works in SQL Server Management Studio

Update: Problem solved, and staying solved. If you want to see the site in action, visit Tweet08
I've got several queries that act differently in SSMS versus when run inside my .Net application. The SSMS executes fine in under a second. The .Net call times out after 120 seconds (connection default timeout).
I did a SQL Trace (and collected everything) I've seen that the connection options are the same (and match the SQL Server's defaults). The SHOWPLAN All, however, show a huge difference in the row estimates and thus the working version does an aggressive Table Spool, where-as the failing call does not.
In the SSMS, the datatypes of the temp variables are based on the generated SQL Parameters in the .Net, so they are the same.
The failure executes under Cassini in a VS2008 debug session. The success is under SSMS 2008 . Both are running against the same destination server form the same network on the same machine.
Query in SSMS:
DECLARE #ContentTableID0 TINYINT
DECLARE #EntryTag1 INT
DECLARE #ContentTableID2 TINYINT
DECLARE #FieldCheckId3 INT
DECLARE #FieldCheckValue3 VARCHAR(128)
DECLARE #FieldCheckId5 INT
DECLARE #FieldCheckValue5 VARCHAR(128)
DECLARE #FieldCheckId7 INT
DECLARE #FieldCheckValue7 VARCHAR(128)
SET #ContentTableID0= 3
SET #EntryTag1= 8
SET #ContentTableID2= 2
SET #FieldCheckId3= 14
SET #FieldCheckValue3= 'igor'
SET #FieldCheckId5= 33
SET #FieldCheckValue5= 'a'
SET #FieldCheckId7= 34
SET #FieldCheckValue7= 'a'
SELECT COUNT_BIG(*)
FROM dbo.ContentEntry AS mainCE
WHERE GetUTCDate() BETWEEN mainCE.CreatedOn AND mainCE.ExpiredOn
AND (mainCE.ContentTableID=#ContentTableID0)
AND ( EXISTS (SELECT *
FROM dbo.ContentEntryLabel
WHERE ContentEntryID = mainCE.ID
AND GetUTCDate() BETWEEN CreatedOn AND ExpiredOn
AND LabelFacetID = #EntryTag1))
AND (mainCE.OwnerGUID IN (SELECT TOP 1 Name
FROM dbo.ContentEntry AS innerCE1
WHERE GetUTCDate() BETWEEN innerCE1.CreatedOn AND innerCE1.ExpiredOn
AND (innerCE1.ContentTableID=#ContentTableID2
AND EXISTS (SELECT *
FROM dbo.ContentEntryField
WHERE ContentEntryID = innerCE1.ID
AND (ContentTableFieldID = #FieldCheckId3
AND DictionaryValueID IN (SELECT dv.ID
FROM dbo.DictionaryValue AS dv
WHERE dv.Word LIKE '%' + #FieldCheckValue3 + '%'))
)
)
)
OR EXISTS (SELECT *
FROM dbo.ContentEntryField
WHERE ContentEntryID = mainCE.ID
AND ( (ContentTableFieldID = #FieldCheckId5
AND DictionaryValueID IN (SELECT dv.ID
FROM dbo.DictionaryValue AS dv
WHERE dv.Word LIKE '%' + #FieldCheckValue5 + '%')
)
OR (ContentTableFieldID = #FieldCheckId7
AND DictionaryValueID IN (SELECT dv.ID
FROM dbo.DictionaryValue AS dv
WHERE dv.Word LIKE '%' + #FieldCheckValue7 + '%')
)
)
)
)
Trace's version of .Net call (some formatting added):
exec sp_executesql N'SELECT COUNT_BIG(*) ...'
,N'#ContentTableID0 tinyint
,#EntryTag1 int
,#ContentTableID2 tinyint
,#FieldCheckId3 int
,#FieldCheckValue3 varchar(128)
,#FieldCheckId5 int
,#FieldCheckValue5 varchar(128)
,#FieldCheckId7 int
,#FieldCheckValue7 varchar(128)'
,#ContentTableID0=3
,#EntryTag1=8
,#ContentTableID2=2
,#FieldCheckId3=14
,#FieldCheckValue3='igor'
,#FieldCheckId5=33
,#FieldCheckValue5='a'
,#FieldCheckId7=34
,#FieldCheckValue7='a'
It is not your indexes.
This is parameter-sniffing, as it usually happens to parametrized stored procedures. It is not widely known, even among those who know about parameter-sniffing, but it can also happen when you use parameters through sp_executesql.
You will note that the version that you are testing in SSMS and the version the the profiler is showing are not identical because the profiler version shows that your .Net application is executing it through sp_executesql. If you extract and execute the full sql text that is actually being run for your application, then I believe that you will see the same performance problem with the same query plan.
FYI: the query plans being different is the key indicator of parameter-sniffing.
FIX: The easiest way to fix this one assuming it is executing on SQL Server 2005 or 2008 is to add the clause "OPTION (RECOMPILE)" as the last line of you SELECT statement. Be forewarned, you may have to execute it twice before it works and it does not always work on SQL Server 2005. If that happens, then there are other steps that you can take, but they are a little bit more involved.
One thing that you could try is to check and see if "Forced Parameterization" has been turned on for your database (it should be in the SSMS Database properties, under the Options page). To tunr Forced Parameterization off execute this command:
ALTER DATABASE [yourDB] SET PARAMETERIZATION SIMPLE
I ran into this situation today and the fix that solved my problem is to use WITH (NOLOCK) while doing a select on tables:
Eg: If your stored proc has T-SQL that looks like below:
SELECT * FROM [dbo].[Employee]
Change it to
SELECT * FROM [dbo].[Employee] WITH (NOLOCK)
Hope this helps.
I've had off-hours jobs fubar my indexes before and I've gotten the same result as you describe. sp_recompile can recompile a sproc... or, if that doesn't work, the sp_recompile can be run on the table and all sprocs that act on that table will be recompiled -- works for me every time.
I ran into this problem before as well. Sounds like your indexes are out of whack. To get the same behavior in SSMS, add this before the script
SET ARITHABORT OFF
Does it timeout as well? If so, it's your indexing and statistics
It's most likely index-related. Had a similar issue with .Net app vs SSMS (specifically on a proc using a temp table w/ < 100 rows). We added a clustered index on the table and it flew from .Net thereafter.
Checked and this server, a development server, was not running SQL Server 2005 SP3. Tried to install that (with necessary reboot), but it didn't install. Oddly now both code and SSMS return in subsecond time.
Woot this is a HEISENBUG.
I've seen this behavior before and it can be a big problem with o/r mappers that use sp_executesql. If you examine the execution plans you'll likely find that the sp_executesql query is not making good use of indexes. I spent a fair amount of time trying to find a fix or explanation for this behavior but never got anywhere.
Most likely your .Net programs pass the variables as NVARCHAR, not as VARCHAR. Your indexes are on VARCHAR columns I assume (judging from your script), and a condition like ascii_column = #unicodeVariable is actually not SARG-able. The plan has to generate a scan in this case, where in SSMS would generate a seek because the variable is the right type.
Make sure you pass all your string as VARCHAR parameters, or modify your query to explicitly cast the variables, like this:
SELECT dv.ID
FROM dbo.DictionaryValue AS dv
WHERE dv.Word LIKE '%' + CAST(#FieldCheckValue5 AS VARCHAR(128)) + '%'