How to retrieve scalar value from stored procedure (ADO.NET) - sql

If in the stored procedure, I just execute one statement, select count(*) from sometable, then from client side (I am using C# ADO.Net SqlCommand to invoke the stored procedure), how could I retrieve the count(*) value? I am using SQL Server 2008.
I am confused because count(*) is not used as a return value parameter of stored procedure.
thanks in advance,
George

Either you use ExecuteScalar as Andrew suggested - or you'll have to change your code a little bit:
CREATE PROCEDURE dbo.CountRowsInTable(#RowCount INT OUTPUT)
AS BEGIN
SELECT
#RowCount = COUNT(*)
FROM
SomeTable
END
and then use this ADO.NET call to retrieve the value:
using(SqlCommand cmdGetCount = new SqlCommand("dbo.CountRowsInTable", sqlConnection))
{
cmdGetCount.CommandType = CommandType.StoredProcedure;
cmdGetCount.Parameters.Add("#RowCount", SqlDbType.Int).Direction = ParameterDirection.Output;
sqlConnection.Open();
cmdGetCount.ExecuteNonQuery();
int rowCount = Convert.ToInt32(cmdGetCount.Parameters["#RowCount"].Value);
sqlConnection.Close();
}
Marc
PS: but in this concrete example, I guess the alternative with just executing ExecuteScalar is simpler and easier to understand. This method might work OK, if you need to return more than a single value (e.g. counts from several tables or such).

When you execute the query call ExecuteScalar - this will return the result.
Executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored.
Since you are only returning one value this would return just the value from your count expression. You will need to cast the result of this method to an int.

marc_s answer worked fine for integer. but for varchar the lenght must be specifed.
cmdGetCount.Parameters.Add("#RowCount", SqlDbType.varchar,30).Direction = ParameterDirection.Output;

Related

Snowflake Variable & Timestamp

I've done a lot of searching, but been unable to find the answer to the problem I have below. Which I'm sure has a very simple answer.
I'm trying to create a static timestamp, which I'll be able to use through out my stored procedure.
So in the instance below, I'm trying to write the CURRENT_TIMESTAMP() to a variable, then calling it in an update statement.
The output I get in the table is "[object Object]", this is currently a varchar column. Ideally want it to input into a timestamp column, but was getting an error.
CREATE OR REPLACE PROCEDURE SP_TEST_RUN()
RETURNS VARCHAR
LANGUAGE JAVASCRIPT
AS
$$
var STORE_DATE1= snowflake.execute({sqlText: "select CURRENT_TIMESTAMP()"});
snowflake.execute({sqlText: "UPDATE MY_TABLE SET TOKEN_1 = '" + STORE_DATE1 +"';" });
$$;
Many thanks in advance!
The execute command returns a resultset from which you need to select the value you want. There are lots of examples of this in the documentation - look for the getColumnValue method
With NickW help, managed to figure it out!
As NickW rightly points out, need to use getColumnValue, this will then loop though the results, as there is only 1 entry. Only needs to occur once.
One thing to note, I had to add "toISOString()" to the variable, which converts the JAVA variable to a TIMESTAMP SQL can understand, otherwise JAVA will automatically convert the Timestamp to a string.
CREATE OR REPLACE PROCEDURE SP_TEST_RUN()
RETURNS VARCHAR
LANGUAGE JAVASCRIPT
AS
$$
var STORE_DATE1= snowflake.execute({sqlText: "select CURRENT_TIMESTAMP()"});
while (STORE_DATE1.next())
{
var STORE_DATE2 = STORE_DATE1.getColumnValue(1);
}
snowflake.execute({sqlText: "UPDATE MY_TABLE SET INSERT_DATE_TIME = '" + STORE_DATE2.toISOString() +"';" });
$$;

"Order by" works in Console but doesn't work in Stored Procedures

I've a problem executing a Stored Procedure in Informix. I'm doing a simple query that it doesn't work. This is the query:
SELECT
first 1 field1,
date1
FROM
historia_t
WHERE
field3 = 1
AND field4 = 1
AND date1 BETWEEN (CURRENT - 1 UNITS YEAR) AND CURRENT
ORDER BY
field1 desc
If I execute the query in DbVisualizer I don't have any problem but if I execute the query in Informix(With stored procedures) I get a sintaxis error in the line with " AND date1 BETWEEN (CURRENT - 1 UNITS YEAR) AND CURRENT " . But the real problem it's in ORDER BY field1 desc;
I don't know why, but sometimes Stored Procedures return errors when you use Order by in them.
Note: Fields are invented because I think they aren't important for the problem.
Thanks in advanced!
When you run a SELECT statement via DB-Access or equivalent, the program takes care of creating a cursor, opening it, fetching the data, closing the cursor, and freeing up the resources used.
Inside a stored procedure, you have to manage this processing. The FOREACH loop does that automatically. If you're using dynamic SQL, there are other statements you can use.
If a SELECT statement may return more than one row, you need the cursor management. If the SELECT statement returns just a single row, you can specify which variable should receive the result. I observe that ORDER BY is immaterial when the SELECT returns a single row — if you have an ORDER BY, there'll be a strong presumption that the query might return more than one row.
For example, this stored procedure works (and returns syssynonyms):
create procedure fk2() returning varchar(128) as tabname;
define t varchar(128);
select tabname into t from informix.systables where tabid = 9;
return t;
end procedure;
But where there's more than one row, you need:
create procedure fk3() returning varchar(128) as tabname;
define t varchar(128);
foreach select tabname into t
from informix.systables
where tabid between 4 and 10
order by tabname # No semicolon permitted (don't ask!)
return t with resume;
end foreach;
end procedure;
This returns:
syscolauth
sysdepend
syssynonyms
syssyntable
systabauth
sysusers
sysviews

Passing array to a store procedure

I want to pass an array of 20k IDs to my stored procedure param in order to update a certain table.
Instead of running 20k update queries separately, I want to run 1 query to update all, it should improve my performances.
Any knows I can I pass a param to my stored proc?
I understood that NVARCHAR(MAX) is limited to 8000 chars, is it possible at all to send such a huge data using stored proc param?
Use a Table Value Parameter instead. See Use Table-Valued Parameters (Database Engine). A TVP is exactly as the name implies: a parameter that is a table. You assign to it from your client code a DataTable and the procedure (or you ad-hoc SQL codE) receives the entire DataTable as a parameter.This is an MSDN copied example:
// Assumes connection is an open SqlConnection.
using (connection)
{
// Create a DataTable with the modified rows.
DataTable addedCategories = CategoriesDataTable.GetChanges(
DataRowState.Added);
// Define the INSERT-SELECT statement.
string sqlInsert =
"INSERT INTO dbo.Categories (CategoryID, CategoryName)"
+ " SELECT nc.CategoryID, nc.CategoryName"
+ " FROM #tvpNewCategories AS nc;"
// Configure the command and parameter.
SqlCommand insertCommand = new SqlCommand(
sqlInsert, connection);
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue(
"#tvpNewCategories", addedCategories);
tvpParam.SqlDbType = SqlDbType.Structured;
tvpParam.TypeName = "dbo.CategoryTableType";
// Execute the command.
insertCommand.ExecuteNonQuery();
}

Why is ##Identity returning null?

I have a .NET 2010 app hitting a SQL2000 db. The code is pretty basic. When I insert a record, the record is inserted, but the id is not returned. The id column is an int and it is an Idetity. Here is the stored proc...
ALTER PROCEDURE Insert_Vendor
#CorpID as varchar(255),
#TaxpayerID as varchar(255)
AS
Insert into dbo.Vendor
(
vdr_CorpID,
vdr_TaxpayerID
)
values
(
#CorpID,
#TaxpayerID
)
IF ##error <> 0
BEGIN
RETURN -1
END
ELSE
RETURN ##Identity
GO
And on the receiving end...
int myID = (int)(db.ExecuteScalar(dbCommand));
You should always use SCOPE_IDENTITY()
NULL can't be returned via RETURN from a stored proc. You'd get a SQL warning and it would return zero.
ExecuteScalar looks for the 1st row, 1st column of a recordset. There is no recordset above
... So you'd use SELECT SCOPE_IDENTITY() not RETURN SELECT SCOPE_IDENTITY()
ExecuteScalar
executes the query, and returns the
first column of the first row in the
result set returned by the query
So you need to re-write the RETURN statements as
SELECT -1
and (since scope_indentity() returns numeric(38,0))
SELECT CAST(SCOPE_IDENTITY() AS INT)
respectively
you have to call ##IDENTITY right after the insert, use Scope_identity() instead.
Because your question leaves out a lot of details I will just mention a few possible ways around this as it seems impossible to answer a question without all the details. But it's your first time here so you'll get better. You will right?
Anyways first I would say you should always use scope_identity as it is safer. There could be things going on behind the scenes with triggers that could cause this real problems. Stick with scope_identity and you shouldn't have to worry.
Second I would suggest instead of
RETURN
use
SELECT SCOPE_IDENTITY()
Lastly I would say why not just use an OUTPUT parameter vs returning a result. I don't have anything to support this next statement but I would think it is better. Again no proof on that but it just seems like less overhead with output parameter vs resultset that comes with schema.
Just my thoughts.
I personally would recommend using SCOPE_IDENTITY instead of ##IDENTITY. That being said the problem is in the stored procedure. Devio above was correct the execute scalar is looking for the first column of the first row. The RETURN statement will not do this so you will need to use either one of the below items:
IF ##error <> 0
BEGIN
Select -1
END
ELSE
Select ##Identity
or:
IF ##error <> 0
BEGIN
Select -1
END
ELSE
Select SCOPE_IDENTITY()

SELECT FROM stored procedure?

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