Retrieve value of a table and using the value in stored procedure - sql

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.

Related

Is there a way to set a parameter from a stored procedure to a var query?

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;
}
}
}

SQL lock row,table on insert and select

I am trying to achieve some sort of lock on sql.
To explain what am i doing simple:
One table with Id int autoincrement as PK, and one field Data varchar(max) non-clustered IX
Now i have some C# code that simlpy checks if the item isn't in the db, makes an insert
The sql code that i am using behind is like:
INSERT INTO {0}.{1} WITH (TABLOCKX) VALUES(#data...)
and the select one is:
SELECT Id FROM {0}.{1} WITH (TABLOCKX) WHERE(Data = #data)
But i can see that there are items with the same value inserted multiple times
TABLOCK creates deadlocks, and i dont want to use unique index because its very slow.
Is there a way to achieve this with locking?
I'm not sure it is what you want, I hope that this reply is helpful.
private void test(string aConnectionString, string aData)
{
using (SqlConnection sqlConnection = new SqlConnection(aConnectionString))
{
sqlConnection.Open();
SqlCommand sqlCommand = sqlConnection.CreateCommand();
SqlTransaction sqlTransaction = sqlConnection.BeginTransaction(System.Data.IsolationLevel.ReadCommitted);
sqlCommand.Connection = sqlConnection;
sqlCommand.Transaction = sqlTransaction;
try
{
sqlCommand.CommandText = #"IF NOT EXISTS(SELECT Id FROM {0}.{1} WHERE Data = #Data)
BEGIN
INSERT INTO {0}.{1}
SELECT #Data
END";
sqlCommand.Parameters.Add("#Data", System.Data.SqlDbType.VarChar).Value = aData;
sqlTransaction.Commit();
}
catch (Exception ex)
{
sqlTransaction.Rollback();
}
}
}

Get the value from Output parameter C#

hi i'm try to create sp in sql with output value
this is the code
ALTER PROCEDURE [dbo].[usp_SelectHospital_IfExiste_Department]
#HospitalDepartmentID INT,
#IfExiste INT OUTPUT
AS
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
IF NOT EXISTS (SELECT c.DeptID FROM Clinic c WHERE DeptID=#HospitalDepartmentID )
BEGIN
SET #IfExiste=0
SELECT
[HospitalDepartmentID],
[NAME]
FROM
[dbo].[Hospital_Department]
WHERE
[HospitalDepartmentID] = #HospitalDepartmentID
END
ELSE
BEGIN
SET #IfExiste=1
SELECT
[HospitalDepartmentID],
[NAME]
FROM
[dbo].[Hospital_Department]
WHERE
[HospitalDepartmentID] = #HospitalDepartmentID
END
and the C# code
public static Hospital_Department GetDepartmentInfo(int ID,int OutIfExist)
{
SqlCommand cmd;
SqlDataReader dr;
Hospital_Department HD = new Hospital_Department();
using (cmd = new SqlCommand("usp_SelectHospital_IfExiste_Department", ProjectCon.GetCon()))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#HospitalDepartmentID", ID);
//cmd.Parameters.Add("#IfExiste",SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add("#IfExiste",SqlDbType.Int);
cmd.Parameters["#IfExiste"].Direction = ParameterDirection.Output;
dr = cmd.ExecuteReader();
while (dr.Read())
{
HD.NAME = dr["NAME"].ToString();
HD.HospitalDepartmentID = Convert.ToInt32(dr["HospitalDepartmentID"]);
}
OutIfExist = Convert.ToInt32(cmd.Parameters["#IfExiste"].Value);
return HD;
}
}
when i try to get the output value is always null
and i run the stored procedure in sql Was run and return the value
so plz tell me what's wrong in my code
thx
Maybe this question has useful info:
According to, http://msdn.microsoft.com/en-us/library/ms971497, you must close the datareader before you process the output parameters.
Hope it helps.

Batch insert/update using stored procedure

Can anyone give me a sample script for batch insert/update of records in table using stored procedure in SQL Server?
I've done something like this in the past:
CREATE PROCEDURE InsertProductIds(#ProductIds xml) AS
INSERT INTO Product (ID)
SELECT ParamValues.ID.value('.', 'VARCHAR(20)')
FROM #ProductIds.nodes('/Products/id') as ParamValues(ID)
END
Obviously this is just a single-column table, but the XML approach applies for multi-column tables as well. You then do this:
EXEC InsertProductIds #ProductIds='<Products><id>3</id><id>6</id></Products>'
Sending a table value parameter is another option.
SQL
CREATE TYPE TestTableType AS TABLE
(
ID INT,
Name NVARCHAR(100),
Description NVARCHAR(2000)
);
GO
CREATE proc [dbo].[Test_Table_Parameter]
#Tbl TestTableType READONLY
as
SELECT 'Return'
GO
Code
var param = new SqlParameter();
param.ParameterName = "#Tbl";
param.SqlDbType = SqlDbType.Structured;
var dt = new DataTable();
var str = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + DateTime.Now;
//map the fields to datatypes here
dt.Columns.Add("ID", typeof (Int32));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Description", typeof(string));
for (var i = 0; i < rows; i++)
{
dt.Rows.Add(new object[] {i + 1, (i + 1).ToString(), str });
}
param.Value = dt;
These were taken from here which also looks at performance of this and the xml approach on the SQL query end.
This looks at performance on the data transmission end. Keep both in mind and the size of the data you are passing back and forth and how it is going to be used in a query to choose the best approach.

How do you specify 'DEFAULT' as a SQL parameter value in ADO.NET?

I have a parameterized SQL query targetted for SQL2005 which is dynamically created in code, so I used the ADO.NET SqlParameter class to add sql parameters to SqlCommand.
In the aforementioned SQL I select from a Table Valued Function with has defaults. I want my dynamic sql to sometimes specify a value for these default parameters, and other times I want to specify that the SQL DEFAULT - as defined in the Table Valued Function - should be used.
To keep the code clean I didn't want to dynamically add the SQL DEFAULT keyword and parameterize it when a non-default is to be used, I just wanted to set DEFAULT as the value of my SQLParameter.
Can I? What is best practice in such an instance?
SQL query parameters take the place of literal values only.
You can't send an SQL keyword as the value of a parameter, just as you cannot send a table identifier, column identifier, list of values (e.g. for an IN predicate), or an expression. The value of the parameter is always interpreted as a literal value, as if you had included a quoted string literal or a numeric literal in your query.
Sorry, but you have to include an SQL keyword as part of the SQL query before you prepare that query.
AFAIK, the only way to tell SQL Server to use a default value is via the DEFAULT keyword or to exclude it from parameter list. That means that the use of the DEFAULT keyword must be in your parameterized SQL Statement. So, something like:
Select ...
From dbo.udf_Foo( DEFAULT, #Param2, #Param3, DEFAULT, .... )
I suppose another approach would be to query the system catalogs for the actual value of the various DEFAULT values and determine whether to set the SqlParameter to the default value that way, but that requires a convoluted second query to get the default values.
If you have the following function (for example):
CREATE FUNCTION dbo.UFN_SAMPLE_FUNCTION
(
#Param1 nvarchar(10),
#Param2 int = NULL
)
RETURNS TABLE
AS
RETURN
SELECT #Param1 AS Col1, #Param2 AS Col2;
GO
Then you can use it the following way (option 1):
SELECT * FROM dbo.UFN_SAMPLE_FUNCTION ('ABC', DEFAULT);
which is correct way and you get the following result:
Col1 Col2
---------- -----------
ABC NULL
But if you try to use parametrized query (option 2):
exec sp_executesql N'SELECT * FROM dbo.UFN_SAMPLE_FUNCTION (#P1, #P2)',N'#P1 nvarchar(10),#P2 int',#P1=N'abc',#P2=default;
you will get an error:
Msg 8178, Level 16, State 1, Line 0
The parameterized query '(#P1 nvarchar(10),#P2 int)SELECT * FROM dbo.UFN_SAMPLE_FUNCTION' expects the parameter '#P2', which was not supplied.
If you have the following .net code:
public void RunTVF(string param1, int? param2)
{
using (SqlConnection con = GetProdConection())
{
using (var cmd = new SqlCommand("SELECT * FROM dbo.UFN_SAMPLE_FUNCTION (#P1, #P2)", con))
{
cmd.CommandType = CommandType.Text;
var param = new SqlParameter
{
ParameterName = "#P1",
SqlDbType = SqlDbType.NVarChar,
Size = 10 ,
Value = param1
};
cmd.Parameters.Add(param);
param = new SqlParameter
{
ParameterName = "#P2",
SqlDbType = SqlDbType.Int,
Value = param2
};
cmd.Parameters.Add(param);
cmd.Connection.Open();
using (IDataReader dataReader = cmd.ExecuteReader())
{
//...
}
}
}
}
then, in case param2 = null as Jack suggested above, the script produced by the code will be identical to the option 2 and will result to the same error. So you cannot use NULL in this case.You cannot set DEFAULT as the value of SQLParameter either.
What you can do is to create a stored procedure to wrap the call to your funcion and move your default value from the function to the SP. Example:
CREATE PROCEDURE dbo.USP_SAMPLE_PROCEDURE
(
#Param1 nvarchar(10),
#Param2 int = NULL, --DEFAULT value now is here (remove it from the function)
#Statement nvarchar(max)
)
AS
BEGIN
SET NOCOUNT ON;
EXEC sp_executesql #Statement,N'#P1 nvarchar(10),#P2 int',#P1=#Param1,#P2=#Param2;
END
The .NET code will look the following way:
public void RunWrapper(string param1, int? param2)
{
using (SqlConnection con = GetProdConection())
{
using (var cmd = new SqlCommand("USP_SAMPLE_PROCEDURE", con))
{
cmd.CommandType = CommandType.StoredProcedure;
var param = new SqlParameter
{
ParameterName = "#Param1",
SqlDbType = SqlDbType.NVarChar,
Size = 10,
Value = param1
};
cmd.Parameters.Add(param);
param = new SqlParameter
{
ParameterName = "#Param2",
SqlDbType = SqlDbType.Int,
Value = param2
};
cmd.Parameters.Add(param);
param = new SqlParameter
{
ParameterName = "#Statement",
SqlDbType = SqlDbType.NVarChar,
Size = -1, //-1 used in case you need to specify nvarchar(MAX)
Value = "SELECT * FROM dbo.UFN_SAMPLE_FUNCTION (#P1, #P2)"
};
cmd.Parameters.Add(param);
cmd.Connection.Open();
using (IDataReader dataReader = cmd.ExecuteReader())
{
//...
}
}
}
}
In this case null as a value for the param2 will be translated to the correct DEFAULT and the following script will be produced:
exec USP_SAMPLE_PROCEDURE #Param1=N'ABC',#Param2=default,#Statement=N'SELECT * FROM dbo.UFN_SAMPLE_FUNCTION (#P1, #P2)'
which will give you the following result:
Col1 Col2
---------- -----------
ABC NULL
I am not sure that this is the best practice. This is just the work-around.
Though you can't set an SQL keyword as the value of a parameter, you could in this case go and get the DEFAULT VALUE.
SELECT COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'table_name' AND COLUMN_NAME = 'column_name'"
if you pass a dot net null value as the parameter value it will use sql DEFAULT
if you pass a dot net DBNull.Value it will use sql NULL