I'm working in a .net app specifically in a validation scripted in a stored procedure. This simple validation checks if there is already a policy with the same policy number that the user is trying to insert and throws an error message.
The problem that I'm facing is of the kind
Procedure or function 'pr_Policy_CheckPolicyNumber' expects parameter '#companyID', which was not supplied.
That's because I added a new field from the same PolicyBill table named (CompanyID).
My question is if it's there a way to set the #CompanyID value directly to the function and fix that error
The stored procedure is
CREATE OR ALTER PROCEDURE [dbo].[pr_Policy_CheckPolicyNumber]
(
#policyNumber VARCHAR(50) ,
#effectiveOn DATETIME ,
#companyID BIGINT
)
AS
IF ( ( SELECT COUNT(pb.policyBillID)
FROM PolicyBill pb
WHERE pb.policyNumber = #policyNumber
AND ( #effectiveOn >= pb.effectiveOn ) and (#effectiveOn <= pb.expiresOn )
AND pb.isActive = 1
AND pb.statusID = 56
AND pb.documentTypeID = 1
AND pb.companyID = #companyID
) > 0 )
BEGIN
PRINT N'The Policy already exists';
SELECT 1
END
ELSE
BEGIN
SELECT 0
END
and the Function is:
private bool CheckPolicyNumber()
{
var result = true;
var query = $"EXEC pr_Policy_CheckPolicyNumber '{txtPolicyNumber.Text}','{deEffectiveON.Date:yyyy/MM/dd}', '#companyID'";
var dt = AhkSqlHelper.ahkExecuteDataTable(query);
result = Convert.ToBoolean(Convert.ToInt16(dt.Rows[0][0].ToString()));
return result;
}
Any help would be appreciated.
Ad mentioned in the comment, the original code is fairly dangerous and you could be open to SQL injection attacks. The best solution is parameterize your command, something like this should do the trick:
using System.Data.SqlClient;
using System.Data;
string connString = "YourConnectionString";
string spName = "pr_Policy_CheckPolicyNumber";
private bool CheckPolicyNumber(string policyNumber, DateTime effectiveOn, long companyID)
{
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(spName, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter parameter1 = new SqlParameter("#policyNumber ", policyNumber);
cmd.Parameters.Add(parameter1);
SqlParameter parameter2 = new SqlParameter("#effectiveOn ", effectiveOn);
cmd.Parameters.Add(parameter2);
SqlParameter parameter3 = new SqlParameter("#companyID ", companyID);
cmd.Parameters.Add(parameter3);
var result = cmd.ExecuteScalar()
return (bool)result;
}
}
}
I have a static string with parameters, being sent to an SQL Execute command.
The strings have the format of delete 'Name' from table where x = 1 and y = 2 or select * from table where x = 1 and y = 2.
My problem is that I need to break the string into parameters.
How do I break the strings so that I can pass the command with the parameters to a single functional with the least possible work?
I have only one function to fix and handle this problem.
From this:
protected object ExecuteScaler(string queryString)
{ OpenConnection(); }
DbCommand command = _provider.CreateCommand();
command.Connection = _connection; command.CommandText = queryString; command.CommandType = CommandType.Text; if (_useTransaction) {
command.Transaction = _transaction; }
try { returnValue = command.ExecuteScalar(); } ...
Can someone please give me an example?
When you build a sql-command like this:
// don't do this because of sql injection
sql = "SELECT * FROM MyTable WHERE Col2 = " + somevalue;
Where you "break out of" the string constant to place a value, that is the point where you want to use a parameter placeholder:
// safe from sql injection
sql = "SELECT * FROM MyTable WHERE Col2 = #somevalue";
And then you can supply the value for #somevalue using the Parameters collection.
When the query needs some fixed values, then it is probably OK to keep them in the string:
// the "type" never changes for this query:
sql = "SELECT * FROM MyTable WHERE type=1 and Col2 = #somevalue";
Can anyone tell me what is going on in this function??
In the following code snippet, user.Id = 0, id.Value = 0 and id.SqlDbType = Int.. as expected since user.Id is an int field.
However, error.Value = null and error.SqlDbType = BigInt. What gives? If I use non-zero it detects an int and the correct value.
Note: the Value properties are the same before and after declaring the parameter direction.
public static long InsertUpdate(User user) {
SqlParameter id = new SqlParameter("#id", user.Id);
id.Direction = ParameterDirection.InputOutput;
cmd.Parameters.Add(id);
SqlParameter error = new SqlParameter("#error_code", 0);
error.Direction = ParameterDirection.Output;
cmd.Parameters.Add(error);
.... other stuff
}
As well, if #SET #error_Code = 0 in the sproc, error.Value = NULL and error.SqlDbType = NVarChar AFTER the procedure runs. If I set it to an integer I get an Int type.
UPDATE:
After specifying SqlDbType.Int the parameter now has the correct SqlDbType before and after the command... however the stored procedure is still setting #error_code = null when I in fact set it to 0.
UPDATE:
When the sproc executes the SELECT statement the #error_code parameter is always returned as null, regardless of when or not it has been set... this only happens when there's a select statement...
Here is the procedure to reproduce:
ALTER PROCEDURE [dbo].[usp_user_insert_v1]
#username VARCHAR(255),
#password VARCHAR(255),
#gender CHAR(1),
#birthday DATETIME,
#error_code INT OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #default_dt DATETIME
EXEC #default_dt = uf_get_default_date
DECLARE #dt DATETIME = GETUTCDATE()
INSERT INTO users(username, password, gender, birthday, create_dt, last_login_dt, update_dt, deleted)
VALUES(#username, #password, #gender, #birthday, #dt, #default_dt, #default_dt, 0)
SELECT * FROM users WHERE id = SCOPE_IDENTITY()
SET #error_code = 3
RETURN
END
SOLUTION?
http://forums.asp.net/t/1208409.aspx?Interesting+problem+with+getting+OUTPUT+parameters+from+SQL+Server+using+C+
Found this link on the ASP forums... apparently you can't read the output parameter until you have read all the results from the SqlDataReader... very unfortunate for me since I decide whether or not I even WANT to read the results based on the output param...
From SqlParameter.Value on MSDN
For output and return value parameters, the value is set on completion of the SqlCommand
i.e. I wouldn't rely on type inference to set the return type implicitly.
I would explicitly set the type of the output parameter:
var error = new SqlParameter("#error_code", SqlDbType.Int)
{
Direction = ParameterDirection.Output
};
Edit
After some reflection of SqlParameter:
The BigInt is easy to explain - it is the default SqlDbType, and the SqlParameter(string parameterName, object value) ctor doesn't overwrite this value.
public enum SqlDbType
{
BigInt = 0,
...
Re: #error_code is returned as NULL
The only thing I can think of is that the PROC fails to complete cleanly. Try moving the SET #error_code = 0 above the EXEC #default_dt = uf_get_default_date ?
Edit
Confirmed, #Damien's point is correct
SqlParameter error = new SqlParameter("#error_code", 0);
Actually calls this ctor:
public SqlParameter(string parameterName, SqlDbType dbType)
whereas
SqlParameter error = new SqlParameter("#error_code", 1234);
calls
public SqlParameter(string parameterName, object value)
Reason : 0 is implicitly castable to enum.
Both of the current answers are slightly incorrect because they're based on the assumption that the constructor being called for your error object is the (string,object) one. This is not the case. A literal 0 can be converted to any enum type1, and such a conversion would be preferred over a conversion to object. So the constructor being called is the (string,SqlDbType) constructor.
So the type is set to BigInt because that's the 0 value for the SqlDbType enumeration, and the Value is null because you have no code that attempts to set the value.
SqlParameter error = new SqlParameter("#error_code", (object)0);
should cause it to select the correct overload.
Demo:
using System;
using System.Data;
namespace ConsoleApplication
{
internal class Program
{
private static void Main()
{
var a = new ABC("ignore", 0);
var b = new ABC("ignore", (object)0);
var c = new ABC("ignore", 1);
int i = 0;
var d = new ABC("ignore", i);
Console.ReadLine();
}
}
public class ABC
{
public ABC(string ignore, object value)
{
Console.WriteLine("Object");
}
public ABC(string ignore, SqlDbType value)
{
Console.WriteLine("SqlDbType");
}
}
}
Prints:
SqlDbType
Object
Object
Object
1From the C# Language specification, version 5, section 1.10 (that is, just in the introduction to the language, not buried deep down in the language lawyery bits):
In order for the default value of an enum type to be easily available, the literal 0 implicitly converts to any enum type. Thus, the following is permitted.
Color c = 0;
I'd have also thought this important enough to be in the Language Reference on MSDN but haven't found a definitive source yet.
Well, it looks like the most reliable way of doing it is by using this overload:
SqlParameter error = new SqlParameter("#error_code", SqlDBType.Int);
error.Value = 0;
The overload you're using takes an object as a parameter, and for some reason which I can't divine, it's not picking the right type.
I'm beginner in SQL Server 2012; I need to generate a product ID in a stored procedure, I generated part of the ID in C#, that part of ID includes Industrialist ID and I pass this to my stored procedure. In the stored procedure I need the last product of my Industrialist number and save in to as SQL variable on my stored procedure. How can I do this?
There are many ways to pass items between SQL and C#, you could use an output parameter where you will populate the parameter within the stored procedure.
string variableName;
using (var conn = new SqlConnection("**connection string**"))
using (var cmd = new SqlCommand("storedProcedureName", conn))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("inputParameter", inputParameter);
var outputParameter = new SqlParameter(){
ParameterName="ParameterName"
,Direction = ParameterDirection.Output
,SqlDbType = SqlDbType.VarChar
,DbType = DbType.VarChar
};
conn.Open();
try
{
cmd.ExecuteNonQuery();
variableName = string.Format("{0}", outputParameter.Value);
}
catch{}
finally
{
conn.Close();
}
}
You could return the value using something along the lines of RETURN #returnValue in your procedure, or you could return it within a table.
string variableName;
using (var conn = new SqlConnection("**connection string**"))
using (var cmd = new SqlCommand("storedProcedureName", conn))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("inputParameter", inputParameter);
conn.Open();
try
{
using (var dbReader = cmd.ExecuteReader())
{
if (dbReader.Read())
{
variableName = string.Format("{0}", dbReader["ColumnName"]);
}
}
}
catch{}
finally
{
conn.Close();
}
}
A generic example of a stored procedure which might work:
CREATE PROC [dbo].[storedProcedureName]
#InputParameter VARCHAR
,#OutputParameter VARCHAR OUTPUT
AS BEGIN
DECLARE #insertedId INT;
BEGIN TRANSACTION
INSERT INTO TableName (...Column Names...)
VALUES (... Values...)
SET #insertedId = SCOPE_IDENTITY()
COMMIT
SELECT #OutputParameter = ColumnName
FROM TableName
WHERE IdColumnName = #insertedId
END
EDIT: Possibly more relevant:
CREATE PROC [dbo].[storedProcedureName]
#IndustrialistId INT
,#OutputParameter VARCHAR OUTPUT -- This might be an int, but it's unclear what you want
AS BEGIN
DECLARE #productId INT;
SELECT #productId = MAX(ProductId)
FROM Products
WHERE IndustrialistId = #IndustrialistId;
SET #OutputParameter = CONVERT(VARCHAR,#IndustrialistId) + '-' + CONVERT(VARCHAR,#productId)
END
If you were to provide some code it might be easier for someone to give you a more tailored response. None of the above code has been syntax checked etc. so should be considered more pseudo code but hopefully it gives you something to work with.
I get a specified cast not valid error when I execute a stored proc like this:
return (int)comm.ExecuteScalar();
When I execute it in SQL Server it returns 1, so I know my proc is working.
What is wrong with my cast?
Updated:
public static int IsPresent(string userName, int inTime)
{
SqlConnection connObj = new SqlConnection();
connObj.ConnectionString = Util.SQLConct();
connObj.Open();
SqlCommand comm = new SqlCommand("usp_IsUserLocked", connObj);
comm.CommandType = CommandType.StoredProcedure;
comm.Parameters.Add(new SqlParameter("#Username", userName));
comm.Parameters.Add(new SqlParameter("#InTime", inTime));
return (int)comm.ExecuteScalar();
}
Thanks in advance
It is possible that your method returns double or int64 or any other type which cannot be implicitly casted to (int). Use Convert.ToInt32 to ensure that your method returns the right type.
using System;
...
return Convert.ToInt32(comm.ExecuteScalar());