SqlCommand.ExecuteScalar - specify a particular data item - vb.net

I have a Stored Procedure which returns 10 columns of data. Using cmd.ExecuteScalar() returns the value of the 1st column from the 1st record.
How can I change this so that I can return different columns, by specifying their alias/dataitem name?
I want to be able to do something like:
Dim FirstName as String = cmd.ExecuteScalar("FirstName")

You could create a method that calls ExecuteReader, and then uses GetOrdinal with your column name to then call GetString.
My VB is non-existent, but this is the C# for an extension method.
public static class SqlCommandExt
{
public static string ExecuteScalar(this SqlCommand cmd, string columnName)
{
using (var reader = cmd.ExecuteReader())
{
if (!reader.Read())
return null;
var index = reader.GetOrdinal(columnName);
return reader.GetString(index);
}
}
}

You can not. Command.ExecuteScalar take no parameters ..
What you can do is to use a text command and modify its CommandText property value to include the column you need to get:
command.CommandText = "SELECT " + columnName + " FROM Table WHERE Key = " + ...

You could create an extension method to do this for you. C# equiv (which I imagine you could translate to a VB.NET extension rather easily):
public static T ExecuteScalar<T>(this SqlCommand cmd, String columnName)
{
using(var reader = cmd.ExecuteReader())
{
var item = default(T);
if(reader.Read())
{
item = (T)dataReader.GetValue(dataReader.GetOrdinal(columnName))
}
return item;
}
}
... and invoke it like so:
var firstName = cmd.ExecuteScalar<String>("FirstName");

You should try the below code also.
Private Sub YourFunctionName()
Using con As System.Data.SqlClient.SqlConnection = New SqlConnection("YourConnection string")
con.Open()
Using cmd As SqlCommand = New SqlCommand
Dim expression As String = "Parameter value"
cmd.CommandType = CommandType.StoredProcedure
cmd.CommandText = "Your Stored Procedure"
cmd.Parameters.Add("Your Parameter Name", SqlDbType.VarChar).Value = expression
cmd.Connection = con
Using dr As IDataReader = cmd.ExecuteReader()
If dr.Read() Then
Dim str As String = dr("YourColumnName").ToString()
End If
End Using
End Using
End Using
End Sub

Related

System.Data.SqlClient.SqlException: Incorrect syntax near "="

I try am trying to build a function that populates a table when given the name of the table and what parameter to order it by.
I think I am just making a syntax error in my SQL command but I can't find it. Please help.
public DataTable populateTable(string tableName, string orderByParameter)
{
DataTable table = new DataTable();
string connString = ConfigurationManager.ConnectionStrings["ConnectionString"].ToString();
string cmdString = "SELECT * FROM (value = #tbl) ORDER BY (parameter = #obp) DESC";
using (SqlConnection conn = new SqlConnection(connString))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandText = cmdString;
cmd.Parameters.AddWithValue("#tbl", tableName);
cmd.Parameters.AddWithValue("#obp", orderByParameter);
using (SqlDataAdapter ad = new SqlDataAdapter(cmd))
{
ad.Fill(table);
}
}
try
{
GridView1.DataSource = table;
GridView1.DataBind();
return table;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return null;
}
}
}
You can't have variables in table name or in 'order by' clause.
You could build the query dynamically as:
string cmdString = "SELECT * FROM [" + tableName + "] ORDER BY " + orderByParameter +" DESC";
With this you won't need to add the parameters #tbl and #obp to the command.
Note that this runs into SQL injection related vulnerabilities. So you shouldn't do this unless you are absolutely certain that the table with given name exists, and the orderByParameter is a valid expression.

How do I cast decimal values to string from my database?

The below code snippet pulls a pack size column from my table but am using getString which I get an error then now see is an issue because the column am pulling is of decimal type. How would I cast my snippet to accept the decimal values?
try
{
string connectionString = "Data Source=CMDLAP121\\SQLEXPRESS;Initial Catalog=TESTBAR;Integrated Security=True";
string query = "SELECT * FROM BCODEREF WHERE BAR_CODE = '" + comboBox1.Text + "';";
string mystring = query;
SqlConnection con = new SqlConnection(connectionString);
con.Open();
SqlCommand cmd = new SqlCommand(query, con);
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
string spo = dr.GetString(dr.GetOrdinal("PACKSIZE"));
ponum.Text = spo;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
Parse to decimal first and convert to a string with the format you need:
decimal packSize= 0;
decimal.TryParse(dr["PACKSIZE"].ToString(), out packSize);
ponum.Text = packSize.ToString("0.00"); //specify format you need
See this post for details of how to set up appropriate string format

Taking one value from a table

sorry if this has been asked before but I everything I found has not helped.
I'm looking to set a value from a table to the text property of a label. This is what I have so far:
In a separate class with the connection string "conn" -
(SQL Region)
Public Const SELECT_1 As String = "SELECT TOP 1 * FROM [TableTimes]
WHERE [timeID] = #PKey"
(Methods Region)
Public Shared Function returnOneRow(PrimaryKey As Integer) As TableTimes
Dim returnRow As New TableTimes(0)
Dim conn As New SqlConnection
conn.connectionstring = Conn.getConnectionString
Dim command As New SqlCommand
command.connection = conn
command.CommandType = CommandType.Text
command.CommandText = SQL.SELECT_1
command.Parameters.AddWithValue("#PKey", PrimaryKey)
Try
conn.Open()
Dim dR As IDataReader = command.ExecuteReader
If dR.Read() Then
returnRow.timeID = PK
If Not IsDBNull(dR(Fields.linkID)) Then returnRow.linkID = dR(Fields.linkID)
If Not IsDBNull(dR(Fields.dateTime)) Then returnRow.dateTime = dR(Fields.dateTime)
End If
Catch ex As Exception
Console.WriteLine(Err.Description)
End Try
Return returnRow
End Function
And then back in the main form I am trying to set the dateTime to a label based on what primary key (timeID) I enter as a parameter. This is the closest I can think of:
label.Text = (Tables.TableTimes.returnOneRow(1).dateTime).ToString
I know the output should be "2016-02-04 10:00:00" for the row with the timeID of 1 based on my table data, but instead it returns "0001-01-01 12:00:00" no matter what parameter I enter.
I would prefer to not change my method or sql statement and just change how I call the function in the main form if that's possible.
Thank you!

Vb.Net/SSIS Script Task - Handling null values

Please see below code (issue with handling null values)
Dts.Variables("File_Name").Value = Framework.GetValue("FileName")
Dts.Variables("File_Id").Value = Framework.GetValue("FileName")
Dts.Variables("File_Name").Value - Data type defined in STRING
Dts.Variables("File_Id").Value - Data type defined in INTEGER
Framework.GetValue - Returns STRING (fetches value stored in database)
Problem - when Framework.GetValue returns nothing because value doesn't exist in database, it throws error in SSIS Script component. How to capture NULL is the problem we are facing
Public Function GetValue(ByVal FetchParameter As String) As String
Dim lGetValue As String = String.Empty
Using Conn New SqlConnection(ConnString)
SQLCommand = New SqlCommand("ParameterValues", _ETLFrameworkConn)
SQLCommand.CommandText = "Select ParamValue from ParameterValues where Parameter_Name=#ParameterField"
SQLCommand.Parameters.Add(New SqlParameter("#ParameterField").Value SqlDbType.NVarChar))
SQLCommand.Parameters("#ParameterField").Value = FetchParameter
Try
Conn.Open()
lGetValue = SQLCommand.ExecuteScalar()
Catch ex As Exception
End Try
End Using
Return lGetValue
End Function
Regards
Try the following code snippet in you GetValue() function. Added the DBNULL handling into the code. If there is no value String.Empty will be written.
Dim lGetValue As String = String.Empty
Using Conn New SqlConnection(ConnString)
SQLCommand = New SqlCommand("ParameterValues", _ETLFrameworkConn)
SQLCommand.CommandText = "Select ParamValue from ParameterValues where Parameter_Name=#ParameterField"
SQLCommand.Parameters.Add(New SqlParameter("#ParameterField").Value SqlDbType.NVarChar))
SQLCommand.Parameters("#ParameterField").Value = FetchParameter
Try
Conn.Open()
var retrunVal = (string)SQLCommand.ExecuteScalar()
IF returnVal = DBNULL.Value Then
lGetValue = returnVal
End
Catch ex As Exception
End Try
End Using
Return lGetValue
Hope this helps!

vb.net call the same function twice from button Event Click

This is my code on button event click function
Dim con As New Koneksi
DataGridView1.Rows.Add(con.getIdTambahBarang(cbBarang.Text), _
con.getNamaTambahBarang(cbBarang.Text), _
con.getHargaTambahBarang(cbBarang.Text), _
txtJumlah.Text)
This is my class Koneksi code :
Public Function getIdNamaHargaTambahBarang(ByVal namaBarang As String, ByVal params As String) As String
Dim id As String = ""
Dim nama As String = ""
Dim harga As String = ""
Try
bukaKoneksi()
cmd.Connection = con
cmd.CommandType = CommandType.Text
cmd.CommandText = "SELECT * FROM barang WHERE nama_barang like '" & namaBarang & "'"
reader = cmd.ExecuteReader
If (reader.Read()) Then
If params = "getNama" Then
nama = reader.GetString(1)
Return nama
End If
If params = "getHarga" Then
harga = reader.GetDouble(2).ToString
Return harga
End If
If params = "getId" Then
id = reader.GetString(0)
Return id
End If
End If
tutupKoneksi()
Catch ex As Exception
End Try
End Function
Public Function getIdTambahBarang(ByVal namaBarang As String) As String
Return getIdNamaHargaTambahBarang(namaBarang, "getId")
End Function
Public Function getNamaTambahBarang(ByVal namaBarang As String) As String
Return getIdNamaHargaTambahBarang(namaBarang, "getNama")
End Function
Public Function getHargaTambahBarang(ByVal namaBarang As String) As String
Return getIdNamaHargaTambahBarang(namaBarang, "getHarga")
End Function
Both of the code above, produces
'System.InvalidOperationException' occurred in System.Data.dll error.
When I debug it, the second call of con produces this error. It seems that in VB.NET, the instance class function only can called once at a time, any solution?
Consider refactoring your code. You're actually hitting the database 3 times, each with a LIKE clause, where you really only need to do this once.
Suggest something like this, which performs the same business logic that you've got, with only one call to your database. It's also got some SQL injection prevention.
Dim con As New Koneksi
Dim barang As Barang = Koneksi.GetBarang()
DataGridView1.Rows.Add(barang.id,
barang.nama, _
barang.harga, _
txtJumlah.Text)
Public Class Koneksi
Public Function GetBarang(nama_barang As String)
Dim barang As New Barang
bukaKoneksi()
cmd.Connection = con
cmd.CommandType = CommandType.Text
cmd.CommandText = "SELECT id,name,harga FROM barang WHERE nama_barang = #nama"
cmd.Parameters.AddWithValue("#nama", namaBarang)
reader = cmd.ExecuteReader
If (reader.Read()) Then
barang.id = reader.reader.GetString(0)
barang.nama = reader.GetString(1)
barang.harga = reader.GetDouble(2).ToString
End If
tutupKoneksi()
Return barang
End Function
End Class
You'll retrieve your barang object properties in one statement. All three properties are gathered from the DB at once. When you inevitably want to add another property to your DataGridView, you won't have to make any extra round-trips to your database, but rather only modify your SQL statement, and the .Rows.Add) call.
The database is now safe from SQL injection in this call.
the code is easier to read and understand for the next developer coming into read this code.
the database was previously using more resources due to being called 3x, and using a LIKE clause, where you really only needed an = name.