SQL Datatable error "Value cannot be null." - asp.net

I am executing a sql query, and I am getting an error Value cannot be null.
Parameter name: dataTable
Code:
strSQLHost = "select HostBase.AppName from HostBase where HostBase.appid=0"
Dim dtHost As DataTable
Dim daHost As SqlDataAdapter = New SqlDataAdapter(strSQLHost, conn)
daHost.Fill(dtHost)
The error occurs at the daHost.Fill(dtHost)
When I run this query in SQL Enterprise manager, I get a value of 'None'. It's a valid value, not a null value.
How can I resolve this?

remove the last ' on your statement
I think it should read like this:
strSQLHost = "select Host.AppName from HostBase where HostBase.appid=0"
And instantiate your DataTable before passing it in:
Dim dtHost As DataTable = new DataTable()

select Host.AppName from HostBase where HostBase.appid=0
Seems like you're mixing table names when you only refer to one table: HostBase. You can't use table: Host in this query without including it in some sort of join (Even if it turned into a Cartesian Product) This is the change.
select HostBase.AppName from HostBase where HostBase.appid=0
Put a break and see the exact value of the string variable: strSQLHost

Related

Retrieve the Id of recently inserted record

I currently have this SQL insert code in code behind
Dim con As New SqlConnection
Dim conString As String
conString = ConfigurationManager.ConnectionStrings("MyConnection").ConnectionString
con = New SqlConnection(conString)
con.Open()
Dim cmd As New SqlCommand("INSERT INTO AdditionalDaysRequest(Status, AdditionalDays, Justification,RequestDaySubmitted) VALUES (#Status,#AdditionalDays,#Justification,#RequestDaySubmitted)", con)
cmd.Parameters.AddWithValue("#Status", "Pending Request")
cmd.Parameters.AddWithValue("#AdditionalDays", TB_Days.Text)
cmd.Parameters.AddWithValue("#Justification", TB_Justification.Text)
cmd.Parameters.AddWithValue("#RequestDaySubmitted", Date.Now)
cmd.ExecuteNonQuery()
con.Close()
The Id in this table is automatically generated and incremented
What I would like to have now is the Id of this record inserted to add it to another table
Change your query text to add a second statement:
...;SELECT SCOPE_IDENTITY();
The SELECT SCOPE_IDENTITY() statement Returns the last identity value inserted into an identity column in the same scope as from the MSDN article above.
In addition, you can use the ability of the Sql engine to understand and process two or more command statements passed as a single string if you separe the statements with a semicolon.
In this way you have the great benefit to execute a single trip to the database.
Dim cmd As New SqlCommand("INSERT INTO AdditionalDaysRequest(Status, " & _
"AdditionalDays, Justification,RequestDaySubmitted) VALUES " & _
"(#Status,#AdditionalDays,#Justification,#RequestDaySubmitted);" & _
"SELECT SCOPE_IDENTITY()", con)
cmd.Parameters.AddWithValue("#Status", "Pending Request")
cmd.Parameters.AddWithValue("#AdditionalDays", TB_Days.Text)
cmd.Parameters.AddWithValue("#Justification", TB_Justification.Text)
cmd.Parameters.AddWithValue("#RequestDaySubmitted", Date.Now)
Dim result = cmd.ExecuteScalar()
con.Close()
if result IsNot Nothing Then
Dim lastInsertId = Convert.ToInt32(result)
End If
Notice that the two statements are now executed using ExecuteScalar instead of ExecuteNonQuery because we want to catch the result of the last command.
You will want to run a new SqlCommand. Set the value of lastInsertId with this statement:
SELECT SCOPE_IDENTITY()
This would be an additional knowledge.
we have multiple options like:
##IDENTITY
SCOPE_IDENTITY
IDENT_CURRENT
All three functions return last-generated identity values. However
IDENT_CURRENT returns the last identity value generated for a specific table in any session and any scope.
##IDENTITY returns the last identity value generated for any table in the current session, across all scopes.
SCOPE_IDENTITY returns the last identity value generated for any table in the current session and the current scope.

SQL - INSERT with Scope_Identity() - getting the record id

I have an ASP.NET page written in VB.NET that gets the items into a GridView by using a SELECT statement with INNER JOIN and also allows you to add an item to the invoice.
INNER JOIN that gets data from items and project_items.
SELECT Items.item_id, Items.item_name, Items.item_cost, project_items.item_quantity
FROM Items
INNER JOIN project_items
ON items.item_id = project_items.item_id
WHERE project_items.project_id = #parameter
#parameter is Session("ProjectID")
(There is a foreign key project_items.item_id -> items.item_id.)
I have an trying to use an SQL statement in VB.NET to try and INSERT into two tables simultaneously. What I tried is I tried to get the item_id of the last record created and insert into another table (project_items) by using that data. However, data is only being entered into the first table.
Any idea what I can do?
This is the code:
Protected Sub btnAddItem_Click(sender As Object, e As EventArgs) Handles btnAddItem.Click
Dim conn As New SqlConnection("Data Source=BRIAN-PC\SQLEXPRESS;Initial Catalog=master_db;Integrated Security=True")
Dim addItemComm As String = "SELECT item_id FROM project_items WHERE project_id=#ProjectID"
Dim user_id_select As New Integer
Dim addItemSQL As New SqlCommand
conn.Open()
addItemSQL = New SqlCommand(addItemComm, conn)
addItemSQL.Parameters.AddWithValue("#ProjectID", Convert.ToInt32(Session("ProjectID")))
Dim datareader As SqlDataReader = addItemSQL.ExecuteReader()
datareader.Close()
conn.Close()
Dim AddNewItemComm As String = "INSERT INTO Items (item_name, item_cost, item_code) VALUES (#ItemName, #ItemCost, #ItemCode); SELECT SCOPE_IDENTITY()"
Dim AddNewItem2Comm As String = "INSERT INTO project_items (item_id, project_id, item_quantity) VALUES (#ItemID, #ProjectID, #ItemQuantity) "
Dim AddNewItemSQL As New SqlCommand
conn.Open()
AddNewItemSQL = New SqlCommand(AddNewItemComm, conn)
AddNewItemSQL.Parameters.AddWithValue("#ItemName", txtItemName.Text.Trim)
AddNewItemSQL.Parameters.AddWithValue("#ItemCost", Convert.ToInt32(txtItemCost.Text))
AddNewItemSQL.Parameters.AddWithValue("#ItemCode", txtItemCost.Text.ToString.ToUpper)
Dim ItemId As Integer
ItemId = AddNewItemSQL.ExecuteScalar()
AddNewItemSQL.ExecuteNonQuery()
conn.Close()
conn.Open()
AddNewItemSQL = New SqlCommand(AddNewItem2Comm, conn)
AddNewItemSQL.Parameters.AddWithValue("#ItemID", ItemId)
AddNewItemSQL.Parameters.AddWithValue("#ProjectID", Convert.ToInt32(Session("ProjectID")))
AddNewItemSQL.Parameters.AddWithValue("#ItemQuantity", Convert.ToInt32(txtItemQuantity.Text))
AddNewItemSQL.ExecuteNonQuery()
conn.Close()
End Sub
Why are you doing this in multiple statements in the first place? Why not:
INSERT dbo.Items (item_name, item_cost, item_code)
OUTPUT inserted.ItemID, #ProjectID, #ItemQuantity
INTO dbo.project_items(item_id, project_id, item_quantity)
VALUES (#ItemName, #ItemCost, #ItemCode);
Now you only have to call one ExecuteNonQuery() and your app doesn't have to care about the actually SCOPE_IDENTITY() value generated. (You can still retrieve SCOPE_IDENTITY() if you want, of course, using ExecuteScalar - but as Nenad rightly points out, pick one instead of calling both.)
Since we now know that there is an explicit foreign key here, we can still reduce your C# code to one call even if we can't use the OUTPUT clause.
DECLARE #i INT;
INSERT dbo.Items (item_name, item_cost, item_code)
SELECT #ItemName, #ItemCost, #ItemCode;
SELECT #i = SCOPE_IDENTITY();
INSERT dbo.project_items(item_id, project_id, item_quantity)
SELECT #i, #ProjectID, #ItemQuantity
SELECT #i; -- if necessary
Would be even cleaner to put this into a stored procedure.
ItemId = AddNewItemSQL.ExecuteScalar()
AddNewItemSQL.ExecuteNonQuery()
These two rows next to each other will execute the command twice. You should remove the second one - ExecuteNonQuery. This will have your data inserted twice in the Items - two same rows but with different IDs.
Since you only retrieve ItemID from the first row, that one should be inserted in project_items, but the other one that was last inserted in items will have no matching row.
Also - complete section from beginning of button click method up before Dim AddNewItemComm As String - where you open and close DataReader and do nothing with it seems completely unnecessary.

How to retrieve SQL Query (last record id) + Execute it in ASP.NET & concatenate (append/prepend) it with a String

I'm trying to retrieve the last ID, in a table, using SQL query and then append the result together with a TextBox value (which is a String):
Dim searchforID = New OleDbCommand("select ID from [table1] where ID = (select max(id) from [table1])", con)
Dim variable1 = searchforID + TextBox1.Text
But it throws this error:
Compiler Error Message: BC30452: Operator '+' is not defined for types
'System.Data.OleDb.OleDbCommand' and 'String'.
Trying to fix it
-- So i tried to convert the returned record ID like this:
Dim variable1 = Convert.ToString(searchforID) + TextBox1.Text
There is no error now but unfortunately the result returned is "System.Data.OleDb.OleDb" + the textbox value, as this example:
System.Data.OleDb.OleDbtest
-- I too thought to convert the returned record ID to integer throws an error:
Exception Details: System.InvalidCastException: Unable to cast object
of type 'System.Data.OleDb.OleDbCommand' to type
'System.IConvertible'.
So why does retrieving the last record ID fail? Might my SQL query be false?
Thank you.
So straight forward solution for problem if someone may find it useful:
Dim searchforID = New OleDbCommand("select MAX(ID) from [table1]", con)
Dim variable1 = searchforID.ExecuteScalar() & TextBox1.Text
Also the answers and comments below have useful information.
Dim variable1 = searchforID.ExecuteScalar() & TextBox1.Text
searchforID is ICommand, not a value, if you want to get a result, you need to execute the command and get result. ExecuteScalar returns first cell value of the first row from query
Dim cmd = New OleDbCommand("select MAX(ID) from [table1]", con)
Dim variable1 = cmd.ExecuteScalar().ToString() & TextBox1.Text
First, if you have command, you should execute the command. There are several ways to execute a DbCommand, depending the type of the command.
Second, if you want the maximum id, go straight and query the maximum! The nested subquery is redundant.
Third, using & to concatenate strings is safer than +. See here for more information.

Accessing sql server temporary table from asp.net

What I am missing to get data from temporary table. This is showing error like Invalid object name #emp. Please help me
I am using Asp.net.
Dim sqlcmd = New SqlCommand("select * into #emp from employees", conn)
sqlcmd.ExecuteNonQuery()
sqlcmd = New SqlCommand("select * from #emp", conn)
Dim dr As SqlDataReader = sqlcmd.ExecuteReader
See Above query is working fine and data is going into temporary table. but it is not selecting again through second one query.
Thanks
Try to use Global Temporary table instead of Local Temporary tabel like.. ##emp
or
You can just use a stored procedure which has all the SQL statement you want to execute and return your desired recordset.

Run query with table name parameter

Dim tbl as String = Request.QueryString("tb") 'tb value = User
Dim sql As String = "Select * From #table Where #Col = #ColVal"
Dim para As New SqlParameter
para.ParameterName = "table"
para.Value = tbl
Dim paraArray1 As New SqlParameter
paraArray1.ParameterName = "#Col"
paraArray1.Value = "Name"
Dim paraArray2 As New SqlParameter
paraArray2.ParameterName = "#ColVal"
paraArray2.Value = "Stephen"
When I try to use DbDataAdapter to run the "sql" command, it gave me this error
Must declare the table variable "#table". Description: An unhandled
exception occurred during the execution of the current web request.
Please review the stack trace for more information about the error and
where it originated in the code.
Exception Details: System.Data.SqlClient.SqlException: Must declare
the table variable "#table".
please advice what should I do to run the sql with given table name as parameter and avoid the sql injection. Thanks a lot!
Parameters are related to stored procedures, you can't specify them in the inline query. You need to concatenate the parameters in the query.
To avoid SQL injection, best approach is to use stored procedures but still if you need to use inline query, check the values before making inline query.
Parameters is valid only for value. Change the SQL string :
Dim sql As String = String.Format("Select * From {0} Where {1} = #ColVal",tableName,ColName)
Write parameter name of table correctly..
para.ParameterName = "#table"
Using SqlParameter avoid Sql Injection in some way as parameters are never inserted directly into statement.....

Resources