I would like to know the difference between these 2 notations.
First of all I have a stored procedure
CREATE PROCEDURE AddSomething( #zonename varchar(50), #desc varchar(255), #TheNewId int OUTPUT ) AS
BEGIN
INSERT INTO a_zone(zonename, descr) VALUES(#zonename, #desc)
SELECT #TheNewId = SCOPE_IDENTITY()
END
What is the difference if I add parameters in this manner
SqlCommand Cmd = new SqlCommand("AddSomething", oConn);
Cmd.CommandType = CommandType.StoredProcedure;
SqlParameter oParam1 = Cmd.Parameters.AddWithValue("#zonename", sName);
SqlParameter oParam2 = Cmd.Parameters.AddWithValue("#desc", description);
and
SqlCommand Cmd2 = new SqlCommand("AddSomething", oConn);
Cmd2.CommandType = CommandType.StoredProcedure;
cmd2.Parameters.Add("#zonename", SqlDbType.VarChar).Value = zonename.Text.Trim();
cmd2.Parameters.Add("#desc", SqlDbType.VarChar).Value = desc.Text.Trim();
Here are some explanations:
difference between command Add and AddWithValue
Dim cmd as new SqlCommand("SELECT * FROM MyTable WHERE MyDate>#TheDate",conn)
cmd.Parameters.Add("#TheDate",SqlDbType.DateTime).Value="2/1/2007"
vs
cmd.Parameters.AddWithValue("#TheDate","2/1/2007")
"Add forces the conversion from string to date as it goes into the parameter. AddWithValue would have simply passed the string on to the SQL Server.
When using Parameters.Add - the SqlDbType is known at compile time
When using Parameters.AddWithValue the method has to box and unbox the value to find out its type.
Additional benefits of the former is that Add is a bit more code safe
and will assist against SQL injection attacks , code safe in terms
that if you try to pass a value that doesn't match the SqlDb type
defined - the error will be caught in .Net code and you will not have
to wait for the round trip back.
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.parameters.aspx
http://msdn.microsoft.com/en-us/library/yy6y35y8.aspx
Edit:
example to get an Output-Parameter:
C#
cmd.Parameters.Add(new SqlParameter("#TheNewId", SqlDbType.Int, int.MaxValue));
cmd.Parameters("#TheNewId").Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
int theNewID = (int)cmd.Parameters("#TheNewId").Value;
VB.Net
cmd.Parameters.Add(New SqlParameter("#TheNewId", SqlDbType.Int, Int32.MaxValue))
cmd.Parameters("#TheNewId").Direction = ParameterDirection.Output
cmd.ExecuteNonQuery()
Dim theNewID As Int32 = DirectCast(cmd.Parameters("#TheNewId").Value, Int32)
When you use AddWithValue, the datatype will be worked out (as best possible) based on the types of the variables passed to the method - assuming sName and description are string variables, the params will be passed in as NVARCHAR.
I personally prefer the 2nd approach, being explicit with the data types (plus I actually specify the sizes too) so that they are guaranteed to match the sproc definition and avoid any unexpected behaviour.
Related
I have a stored procedure in SQL Server that returns two values. When called from QA with the following SQL code:
exec TWEEPush_ValidateCO #CoFilter='CO IN(''1502'',''Mike'',''Clarkson'')', #TDate='09/18/`2017'
it works as expected by returning two values:
#TempCOID #TempDate
1502 09/10/2017
The stored procedure does some work and ends with the two values being set to non null values, with the stored procedure ending with:
SELECT
#TempCOID AS N'#TempCOID',
#TempDate AS N'#TempDate'
In VB.net (Visual Basic, not C), I've tried many different approaches to get the results but have had no luck. Either I get an error saying the named param doesn't exist, or it ends up returning empty values (everything is coded to prevent Nulls in the return data)
Dim sConnectStr As String = GetSQLConnectionString()
Try
Using Connection As New SqlConnection(sConnectStr)
Connection.Open()
Dim Command As New SqlCommand("dbo.TWEEPush_ValidateCO", Connection)
Command.CommandType = CommandType.StoredProcedure
Command.Parameters.AddWithValue("#CoFilter", Filter)
Command.Parameters.AddWithValue("#TDate", Now())
Dim PramCOIDRet As New SqlParameter
PramCOIDRet.ParameterName = "#TempCOID"
PramCOIDRet.SqlDbType = SqlDbType.NVarChar
PramCOIDRet.Size = 30
PramCOIDRet.Direction = ParameterDirection.Output
Dim PramDateRet As New SqlParameter
PramDateRet.ParameterName = "#TempDate"
PramDateRet.SqlDbType = SqlDbType.NVarChar
PramDateRet.Size = 30
PramDateRet.Direction = ParameterDirection.Output
Command.Parameters.Add(PramCOIDRet)
Command.Parameters.Add(PramDateRet)
Command.ExecuteNonQuery()
Dim COID as string = Command.Parameters("#TempCOID").Value
Dim CoDate as Date = CDate(Command.Parameters("#TempDate").Value)
End Using
Catch ex As Exception
End Try
No matter what code I've tried, the code never returns the data as expected.
What am I doing wrong? Can someone please shed some light on this please?
You didn't show us your stored procedure code - but most likely, it's something like this:
CREATE PROCEDURE dbo.dbo.TWEEPush_ValidateCO
#CoFilter VARCHAR(100), -- just guessing here!
#TDate DATE -- again - just guessing
AS
BEGIN
DECLARE #TempCOID INT;
DECLARE #TempDate DATE;
-- do some calculations here that define #TempCOID and #TempDate
-- this is just for demo purposes - I'm sure your calculation is a bit
-- more complex and involved...
SET #TempCOID = 1502;
SET #TempDate = '20170910';
-- return the values in a SELECT statement
SELECT
#TempCOID AS N'#TempCOID',
#TempDate AS N'#TempDate'
END
In this case, you're returning a RESULT SET - not two parameters!
You need to get your values like this:
static void Main(string[] args)
{
string connectionString = ConfigurationManager.ConnectionStrings["YourConnectionString"].ConnectionString;
int tempCoid;
DateTime tempDate;
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand("dbo.dbo.TWEEPush_ValidateCO", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#CoFilter", Filter);
cmd.Parameters.AddWithValue("#TDate", DateTime.Now);
conn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
tempCoid = rdr.GetFieldValue<int>(0);
tempDate = rdr.GetFieldValue<DateTime>(1);
}
}
conn.Close();
}
}
(I'm sure you get the idea - and you can easily translate this into VB.NET, too).
Hope that helps!
Marc
I am receiving this error:
Procedure or function 'usp__SingleSelectServerRackName' expects parameter '#chvServerName', which was not supplied.
I looked up the error and did not find any applicable solutions.
I was successfully able to run the Proc and retrieve out put information, and was able to successfully retrieve value of cbserver.valuemember in command window.
Any suggestions to correct this problem?
Here is my code:
Imports System.Data.SqlClient
Try
Dim connString As String = "server=ServerName;database=DatabaseName;trusted_connection=yes"
Using connection As New SqlConnection(connString)
'Create the command and set its properties.
Dim SingleSelectServerRackName As SqlCommand = New SqlCommand
SingleSelectServerRackName.Connection = connection
SingleSelectServerRackName.CommandText = "usp__SingleSelectServerRackName"
SingleSelectServerRackName.CommandType = CommandType.StoredProcedure
'Add the input parameter and set its properties
Dim ParamSingleSelectServerName As New SqlParameter()
ParamSingleSelectServerName.ParameterName = "#chvServerName"
ParamSingleSelectServerName.SqlDbType = SqlDbType.VarChar
ParamSingleSelectServerName.Direction = ParameterDirection.Input
ParamSingleSelectServerName.Value = cbServer.SelectedValue.ToString()
Dim ParamSingleSelectServerRackName As New SqlParameter
ParamSingleSelectServerName.ParameterName = "#numServerRackName"
ParamSingleSelectServerRackName.SqlDbType = SqlDbType.VarChar
ParamSingleSelectServerRackName.Direction = ParameterDirection.Output
ParamSingleSelectServerRackName.Size = 50
'Add the parameters to the Parameters collection
SingleSelectServerRackName.Parameters.Add(ParamSingleSelectServerName)
SingleSelectServerRackName.Parameters.Add(ParamSingleSelectServerRackName)
'Open database connection
connection.Open()
'Execute data reader
Dim readerSingleSelectServerRackName As SqlDataReader = SingleSelectServerRackName.ExecuteReader()
readerSingleSelectServerRackName.Close()
cbRackName.ValueMember = SingleSelectServerRackName.Parameters("#numServerRackName").Value.ToString
'Close database connection
connection.Close()
End Using
Catch ex As Exception
MsgBox(ex.Message)
MsgBox(ex.StackTrace)
End Try
Proc:
CREATE Procedure usp__SingleSelectServerRackName
(
#chvServerName AS varchar(50), ---Input variable #chvServerName displays
#numServerRackName AS varchar(50) OUTPUT ---Output variable #numServerRackName
)
AS Begin
IF #chvServerName is null or len(ltrim(#chvServerName)) = 0 ---Check for null value
RAISERROR('Servername cannot be blank.',16,1)
SELECT Rcknm.nm
FROM Rcknm
INNER JOIN Srvr
on srvr.fk_rcknm = Rcknm.ID
WHERE srvr.nm = #chvServerName
End
Looks like you missed something on your copy/paste of parameters.
ParamSingleSelectServerName.ParameterName = "#numServerRackName"
ParamSingleSelectServerName.ParameterName = "#chvServerName"
Your second parameter is overwriting your first. Try this instead.
ParamSingleSelectServerRackName.ParameterName = "#numServerRackName"
Name of the 2nd parameter is same so overwriting it
Look at these two lines
Dim ParamSingleSelectServerRackName As New SqlParameter
ParamSingleSelectServerName.ParameterName = "#numServerRackName"
You are declaring the second parameter, but then you set the name intended for the second parameter to the first parameter.
That's the missing parameter, you have no more a parameter called #chvServerName
You are really making your life difficult. Why not just calling the twos #Rack and #Server ?
I have created a code to take data from one database and place it into a second database, the problem i am having currently is when a field in the database is null it returns an error
"Conversion type 'DBNULL' to type 'String' is not valid"
The code I am using is:
Dim ITN As String = ResultSet.Item( "ItemNumber")
Dim QN As String = ResultSet.Item( "QuoteNumber")
Dim ITD As String = ResultSet.Item( "ItemDescription")
Dim DET As String = ResultSet.Item( "Details")
Dim PR As String = ResultSet.Item("Price")
Hoping someone can assist with this one!!
You can use a ternary statement and check if the Item is null before casting it to a string.
Also in c# you could do something like this:
String value = ResultSet.Item("Price") as String;
The as will convert an invalid reference type to null automatically. For VB.NET:
VB.Net equivalent of C# "As"
I got tired of checking for DBNULL so i wrote a function for that. Depending on the type of database you are working with it really depends but, For efficiency, you'd probably want to use the StringBuilder class rather than string concatenation.
If you use a parameterized query see this link for a very basic introduction to using parameterized queries with Access, you would be able to directly insert the special DBNull value:
Dim myConnection As New OleDbConnection(DBConnection)
Dim Cmd As OleDbCommand = New OleDbCommand()
Cmd.CommandText = "INSERT INTO dbTable (ItemNumber, QuoteNumber, ItemDescription, Details, Price) VALUES (#ITN, #QN, #ITD, #DET, #PR)"
Cmd.Parameters.Add(New OleDbParameter("#ITN", OleDbType.VarChar)).Value = CheckDBNull(ITN)
Cmd.Parameters.Add(New OleDbParameter("#QN", OleDbType.VarChar)).Value = CheckDBNull(QN)
Cmd.Parameters.Add(New OleDbParameter("#ITD", OleDbType.VarChar)).Value = CheckDBNull(ITD)
Cmd.Parameters.Add(New OleDbParameter("#DET", OleDbType.VarChar)).Value = CheckDBNull(DET)
Cmd.Parameters.Add(New OleDbParameter("#PR", OleDbType.VarChar)).Value = CheckDBNull(PR)
DBConnection.Open()
Cmd.ExecuteNonQuery()
this is also good for avoiding nasty SQL Injection. Like I mentioned, depending on the database you are using you might have to use SqlParameter & SqlDbType vs. OleDbParameter & OleDbType but The CheckDBNull function could be a simple as the following:
Private Function CheckDBNull(ByVal s As String) As Object
If Not s Is Nothing And s.Length > 0 Then
Return s
Else
Return System.DBNull.Value
End If
End Function
I hope this helps. please note some of these parameters were just used as an example (myConnection, Cmd, dbTable) as you did not provide db info:
I have a stored procedure like this:
ALTER PROCEDURE [dbo].[T_TransactionSummary]
#startDate datetime,
#endDate datetime,
#locations integer
AS
BEGIN
.................
................
WHERE (Transaction_tbl.dtime BETWEEN #fromDate AND #toDate)
AND (Location_tbl.Locid IN (#locations))
I've got a ListBox which populates the #locations parameter (an integer), and two DateTimePicker controls for the #fromDate and #toDate.
I took my listbox value like this:
cnt = LSTlocations.SelectedItems.Count
Dim list As New List(Of Integer)
Dim locid As Integer
If cnt > 0 Then
For i = 0 To cnt - 1
Dim locationanme As String = LSTlocations.SelectedItems(i).ToString
locid = RecordID("Locid", "Location_tbl", "LocName", locationanme)
list.Add(locid)
Next
End If
Dim da As New SqlDataAdapter
Dim ds As New DataSet
Dim cmd23 As New SqlCommand("T_TransactionSummary", con.connect)
cmd23.CommandType = CommandType.StoredProcedure
cmd23.Parameters.Add("#startDate", SqlDbType.NVarChar, 50, ParameterDirection.Input).Value = startdate
cmd23.Parameters.Add("#endDate", SqlDbType.NVarChar, 50, ParameterDirection.Input).Value = enddate
cmd23.Parameters.Add("#locations", SqlDbType.Int).Value = String.Join(",", list)
da.SelectCommand = cmd23
da.Fill(ds)
if the code reach here i am getting error like this:
"Failed to convert parameter value from a String to a Int32
i know am getting error in this line
cmd23.Parameters.Add("#locations", SqlDbType.Int).Value = String.Join(",", list)
i want go the parameter to stored procedure like 1,2,3 only
i am using vb.net. what is wrong with my code..any help is great appreciate ..
If you define your stored procedure parameters are DATETIME (good thing!):
#startDate datetime,
then you must also define them as such in your VB.NET code!!
This is wrong:
cmd23.Parameters.Add("#startDate", SqlDbType.NVarChar, 50, ParameterDirection.Input).Value = startdate
It should be:
cmd23.Parameters.Add("#startDate", SqlDbType.DateTime).Value = ........
At this line:
cmd23.Parameters.Add("#locations", SqlDbType.Int).Value = String.Join(",", list)
You are producing a string like 1,2,3,4,5
Then you need to delete the delimitter when joining the list:
String.Join("", list)
That will produce a serie of numbers like 12345
SQL Server does not currently support the functionality as you describe (although I wish it did, I have this same problem.) If you have the ability to create objects on SQL server, you can create what is called a Table-Valued Parameters AKA parameters in the shape of a table.
Basically you create a "table type" on the server. It is an empty table that describes the shape of data table that you can pass to a parameter. In your case you would create a table with one column.
Let's walk through this example. Create your table type object on SQL server:
CREATE TYPE dbo.CategoryTableType AS TABLE
( CategoryID int, CategoryName nvarchar(50) )
Now in your stored procedures, or dynamic SQL in your code, you can declare table-valued parameters based on that type. This creates a stored procedure with one input parameter of type dbo.CategoryTableType. Now you can pass in a rows with columns CategoryID and CategoryName. Notice it must be read only.
CREATE PROCEDURE usp_UpdateCategories
(#tvpNewCategories dbo.CategoryTableType READONLY)
Now you can pass values to your parameterized SQL statement. Notice your SQL Parameter must be of type SqlDBType.Structured.:
Dim sqlParameter As New SqlClient.SqlParameter
sqlParameter.ParameterName = "#tvpNewCategories"
sqlParameter.SqlDbType = SqlDbType.Int
sqlParameter.Value = addedCategories
sqlParameter.TypeName = "dbo.CategoryTableType"
You create your input data as a VB or C# DataTable:
'Create a DataTable with the modified rows.
Dim addedCategories As DataTable = _
CategoriesDataTable.GetChanges(DataRowState.Added)
More info: http://msdn.microsoft.com/en-us/library/bb675163(v=vs.110).aspx
Side note: the simplest, but least elegant, way to do this is to have dynamic SQL in your code and do a string.replace and replace #tvpNewCategories with (1, 2, 3, 4)
I am trying to retrieve some rows from the database using simple SELECT statement in SQL and displaying them in a Data Grid, Now what I have to do is to multiply the retrieved values with some factor and then display it. I am trying to achieve it the following way:
I have declared PerDoseSize1 as a double variable which gets its value from a function. I am not able to do it this way.
It gives me an error saying "PerDoseSize1 is not a valid column"
public void FillDG1(string Chemical_Name0, string Chemical_Name1, string Chemical_Name2, string Chemical_Name3,double PerDoseSize1)
{
objDs.Clear();
string connString ="Data Source=dk1;Integrated Security=True";
SqlConnection con = new SqlConnection(connString);
con.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = "SELECT [Chemical Name],([GWP])*(perdosesize) AS GlobalWarming, ([ODP])*(perdosesize) AS OzoneDepletion, [WDP] AS WaterDepletion ,[FDP] AS FossilDepletion FROM [Surfactants$] WHERE ([Chemical Name] IN ( #ChemicalName0, #ChemicalName1,#ChemicalName2 ,#ChemicalName3)) ";
cmd.Parameters.AddWithValue("#ChemicalName0",Chemical_Name0);
cmd.Parameters.AddWithValue("#ChemicalName1", Chemical_Name1);
cmd.Parameters.AddWithValue("#ChemicalName2", Chemical_Name2);
cmd.Parameters.AddWithValue("#ChemicalName3", Chemical_Name3);
cmd.Parameters.AddWithValue("#perdosesize", PerDoseSize1);
SqlDataAdapter dAdapter = new SqlDataAdapter();
dAdapter.SelectCommand = cmd;
dAdapter.Fill(objDs);
DataTable myDataTable = objDs.Tables[0];
DG1.DataContext = objDs.Tables[0].DefaultView;
cmd.ExecuteNonQuery();
MessageBox.Show(ChemicalName0,ChemicalName1);
con.Close();
}
It still doesn't seem to work, Is it still wrong? Please help!
The way you have written it:
"SELECT ([GWP])*(PerDoseSize1) AS GlobalWarming, ([ODP])*(PerDoseSize1)
Will not work because the function argument you're passing in won't be substituted in your SQL.
So you can try creating a Parameter argument for PerDoseSize1 and pass it into the SQL, like you're doing with AddWithValue.
I have declared PerDoseSize1 as a
double variable which gets its value
from a function
So what? How does that get into the SQL? So far there is NOTHING saying this. YOU have to put it into the SQL and assign it to a parameter. It wont magically hook up.