IF EXISTS IN STORED PROCEDURE - asp.net

I am using following storedprocedure
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
Alter PROCEDURE [dbo].[GetUserDetailsByUserID]
(
#UserId varchar(100)
)
AS
BEGIN
IF EXISTS(Select * from Registration where UserId=#UserID)
BEGIN
Select
[Name],
[UserId],
[PermanentAddress],
[TemporaryAddress],
[OfficePhoneNo],
[ResidentialPhoneNo],
[MobileNo],
[Email],
[ContactPerson],
[C_OfficePhoneNo],
[C_ResidentialPhoneNo],
[C_MobileNo],
[C_Email],
[Project],
[TotalAmount]
From
Registration
Where
UserId=#UserId
END
END
I am using following code in vb
Public Function GetUserDetailsByUserID(ByVal strUserId As String) As DataTable
Try
Dim db As Database = DatabaseFactory.CreateDatabase()
Dim DbCommand As DbCommand = _
db.GetStoredProcCommand("GetUserDetailsByUserID")
db.AddInParameter(DbCommand, "#UserId", DbType.String, strUserId)
Return db.ExecuteDataSet(DbCommand).Tables(0)
Catch ex As Exception
Return New DataTable()
End Try
End Function
If details corresponding to userid does not exist in registration table, db.ExecuteDataSet(DbCommand).Tables(0) shows one error as cannot find Table(0). What modification in stoted procedure i hve to make to get rid of this error?

You can simply get rid of the IF EXISTS. When the record doesn't exist, you will get an empty table (which I think is what you want, looking at your sample code)

The procedure will not always return a record set. If there is no record set then Tables will be empty and Tables(0) will fail and return an error. You should just return the selection rather than only selecting if the record exists. Your code can then check for an empty returned record set.

In the VB code, change
Return db.ExecuteDataSet(DbCommand).Tables(0)
to
Dim Ds as DataSet = db.ExecuteDataSet(DbCommand)
If Ds.Tables.Count = 1 Then
Return Ds.Tables(0)
Else
Return New DataTable()
End If
Also, remove the If Exists from the Stored Procedure, since if the row exists, you will force the database to search twice in the table for the record where UserId=#UserID.

Related

How to store the value of last inserted id(PK) into a variable where the primary key is a GUID in VB.Net

My question is related to the question asked in here How to get last inserted id?
But the scope_identity() will not work for me as in my case the primary key value for the table is a GUID value.
Also I have seen the question in here
SQL Server - Return value after INSERT
but the link does not explain how can i store the value in a variable. I need to store the value in a variable which I can use for multiple entry.
I am inserting hard coded value into multiple SQL Server tables. All the primary key columns are GUID.
The table structure are as follows.
This is the code I use to insert data into survey table.
Protected Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
Dim survey = Guid.NewGuid().ToString()
Dim SurveyTitle As String = "Diversity Monitoring Survey"
Dim SurveyDetail As String = ""
Core.DB.DoQuery("insert into survey(id,title, detail,employerid,userid) values(#id,#title, #detail, #eid, #uid);", Core.DB.SIP("title", SurveyTitle), Core.DB.SIP("detail", SurveyDetail), Core.DB.SIP("eid", LocalHelper.UserEmployerID()), Core.DB.SIP("uid", LocalHelper.UserID()), Core.DB.SIP("id", survey))
End Sub
Where DoQuery is
Shared Sub DoQuery(ByVal commandText As String, ByVal ParamArray params As SqlParameter())
Dim conn As SqlConnection = Nothing
Try
conn = GetOpenSqlConnection()
DoQuery(conn, commandText, params)
Finally
If conn IsNot Nothing Then conn.Dispose()
End Try
End Sub
Now I want to retrieve of just inserted SurveyId value and store it into a variable strSurveyId
Dim strSurveyID As String
So that I can insert that value in the table SurveyQuestionCategory:
Core.DB.DoQuery("insert into surveyquestioncategory(title, detail, surveyid) values(#title, #detail, #sid)", Core.DB.SIP("title", strSurveyQuestionCategoryTitle), Core.DB.SIP("detail", strSurveyQuestionCategoryDetail), Core.DB.SIP("sid", strSurveyID))
scope_identity() will not work in my case as the the is GUID.
I have tried this
SELECT * from [MPBlLiteDev].[dbo].[Survey] where id=SCOPE_IDENTITY()
But it gives me a error
Operand type clash: uniqueidentifier is incompatible with numeric
Please suggest with code.
Please go through the below stored procedure
Create proc SPInsertSurvey
(
#Title varchar(MAX),
#OutSurveyID UNIQUEIDENTIFIER output
)
as
DECLARE #Table TABLE (SurveyID UNIQUEIDENTIFIER)
begin
insert into survey(Title)
Output inserted.SurveyID into #Table values (#Title)
set #OutSurveyID =(select SurveyID from #Table)
end
You can execute it by using below Syntax
DECLARE #return_value int,
#OutSurveyID uniqueidentifier
EXEC #return_value = [dbo].[SPInsertSurvey]
#Title = N'''S1''',
#OutSurveyID = #OutSurveyID OUTPUT
SELECT #OutSurveyID as N'#OutSurveyID'
SELECT 'Return Value' = #return_value
Hope this will help
SCOPE_IDENTITY() will only return the newly generated Identity value if there is any, for GUID values you would need a table variable with OUTPUT clause in your insert statement something like this.....
DECLARE #NewIDs TABLE (ID UNIQUEIDENTIFIER)
insert into survey(id,title, detail,employerid,userid)
OUTPUT inserted.id INTO #NewIDs(ID)
values(#id,#title, #detail, #eid, #uid);
SELECT * FROM #NewIDs

SQL parameters asp.net(vb.net)

Sorry for my bad English.I have a problem in my code:
Dim sq As String = "SELECT username FROM standing WHERE username = #user"
Dim con As New SqlConnection(Sql.ConnectionString)
Dim cmd As New SqlCommand(sq, con)
cmd.Parameters.Add("#user", SqlDbType.VarChar)
cmd.Parameters("#user").Value = "contesttest"
con.Open()
Dim index As Integer = cmd.ExecuteNonQuery
con.Close()
If (index > 0) Then
'Something..
Else
'Something else..
End If
in my code,"contesttest" is exists in Database and returnedrows(index) should be greater than 0.But index is -1 !What's the problem?
my connectionstring is right.
It does not matter if C# or VB.Net
If your username field is an unique index (meaning that you don't have two username with the same value) then your query could be rewritten without using a SqlDataReader
Dim sq As String = "SELECT username FROM standing WHERE username = #user"
Using con SqlConnection(Sql.ConnectionString)
Using cmd As New SqlCommand(sq, con)
cmd.Parameters.Add("#user", SqlDbType.VarChar)
cmd.Parameters("#user").Value = "contesttest"
con.Open()
Dim username = cmd.ExecuteScalar
If userName IsNot Nothing Then
'Something..
Else
'Something else..
End If
End Using
End Using
ExecuteScalar return the first column of the first row retrieved by your command. In the case you column is a unique index/primary key then you have just one row and you return just the username. So if there is something returned then you have found your user
From MSDN;
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. When a trigger exists on a
table being inserted or updated, the return value includes the number
of rows affected by both the insert or update operation and the number
of rows affected by the trigger or triggers. For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.
This is not a problem. It is a definition of ExecuteNonQuery method.
Use a Reader of some sort (like a SqlDataReader) to get the number of rows returned from a SELECT statement or ExecuteScalar to get a single returned value. Using ExecuteNonQuery will only return the number of rows affected when used with a SELECT statement.
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. When a trigger exists on a
table being inserted or updated, the return value includes the number
of rows affected by both the insert or update operation and the number
of rows affected by the trigger or triggers. For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.
Read about it on MSDN.
i guess SqlDbType.VarChar will allow only one character ..you need to pass length also for varchar.
for Example:-
cmd.Parameters.Add("#user", SqlDbType.VarChar,80)

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.

Executenonquery return value

I want to perform a search on a table to see if record exists. I do not want to perform insert or update after. I have done this already but somehow I cannot get this to work. On my asp.net page I cannot seem to get any value returned. The error is "input string not in correct format" I ma sure it is obvious but I cannot seem to see it now!
here is my code:
Dim con As New SqlConnection("connstring")
Dim cmd As New SqlCommand("checkname", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add(New SqlParameter("#d", SqlDbType.Int))
cmd.Parameters("#id").Value = TextBox1.Text
Dim para As New SqlParameter
para.Direction = ParameterDirection.ReturnValue
para.ParameterName = "returnvalue"
cmd.Parameters.Add(para)
con.Open()
cmd.ExecuteNonQuery()
Dim exists As Integer
exists = Convert.ToInt32(cmd.Parameters("returnvalue").Value)
If exists = 1 Then
Label1.Text = "You......"
ElseIf exists = 0 Then
Label1.Text = "You....."
End If
con.Close()
stored procedure:
CREATE PROCEDURE checkname
-- Add the parameters for the stored procedure here
#id int
AS
--This means it exists, return it to ASP and tell us
-- SELECT 'already exists'
IF EXISTS(SELECT * FROM attendees WHERE id = #id)
BEGIN
RETURN 1
END
ELSE
BEGIN
RETURN 0
END
You need to ensure that you are passing an integer.
int intValue;
if(!int.TryParse(TextBox1.Text, out intValue))
{
// Update your page to indicate an error
return;
}
cmd.Parameters.Add(New SqlParameter("id", SqlDbType.Int));
cmd.Parameters("id").Value = intValue;
(Technically you don't need the "#" character when
defining the parameters in the .NET
code.)
You have declared your procedure parameter as #d instead of #id. Also a return parameter cannot be an input parameter. The return value should be an exit code. You most likely want to create an output parameter and set that to 1 or zero inside of your stored procedure.
Edit: to clarify, the return value is generally regarded as an indicator of correct execution. Zero usually means success, where any other numeric value is generally regarded as an error code. That is why I recommended adding an output parameter instead of adding a return value parameter.
ExecuteNonQuery returns the number of rows affected. Therefore the return values that you set in your stored procedure are thrown away and will not be returned by the ExecuteNonQuery method.
ExecuteNonQuery is used to Insert / Delete / Update operations. Not for SELECT, you need either ExecuteScalar or ExecuteReader methods. This link will help you to know how to use output parameters : http://aspdotnet-suresh.blogspot.com/2010/10/introduction-here-i-will-explain-how-to.html

SQL Stored Procedures failing to return values

I am working on a Tag system for a news page designed in ASP.NET. For the system I require a TagExists method to check for tags within the database. The stored procedure I have written is below.
ALTER PROCEDURE [dbo].[Tags_TagExists](
#Tag varchar(50))
AS
BEGIN
If (EXISTS(SELECT * FROM dbo.Tags WHERE LOWER(#Tag) = LOWER(Tag)))
RETURN 1
ELSE
RETURN 0
END
When I call this method however 0 is always returned. I am using the following code to call the method
Public Shared Function TagExists(ByVal name As String) As Boolean
Dim result As Boolean
Using conn As SqlConnection = New SqlConnection(ConnectionString)
Dim cmd As New SqlCommand("Tags_TagExists", conn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#Tag", name)
conn.Open()
result = Convert.ToBoolean(cmd.ExecuteScalar())
conn.Close()
End Using
Return result
End Function
I have tried switching the procedure to return 0 if the tag exists and 1 if it does not and it still returns 0 despite the exact same testing conditions. I have also returned the actual select query and it has complained of the Tag "news" (my test item) not being an int on execution showing the select itself is definitely properly formed.
If anyone can shed some light on this, Thanks
Michael
It should probably be a function, but here is the stored proc code:
ALTER PROCEDURE [dbo].[Tags_TagExists](
#Tag varchar(50))
AS
BEGIN
If EXISTS(SELECT 1 FROM dbo.Tags WHERE LOWER(#Tag) = LOWER(Tag))
BEGIN
SELECT 1
END
ELSE
BEGIN
SELECT 0
END
END
You're returning from a Stored Procedure, not getting a single scalar value from a SQL statement.
I'm assuming this is a simple example and you have other processing you want to handle inside the Stored Procedure. In that case, using the Stored Procedure and return value is the right way to go. You need to handle the return value from the Stored Procedure in your C# code (Please excuse any syntax errors, my VB.NET is a bit rusty):
Public Shared Function TagExists(ByVal name As String) As Boolean
Dim result As Boolean
Using conn As SqlConnection = New SqlConnection(ConnectionString)
Dim cmd As New SqlCommand("Tags_TagExists", conn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#Tag", name).
Dim retVal As SqlParameter = _
cmd.Parameters.Add("return_value", SqlDbType.Int)
retval.Direction = ParameterDirection.ReturnValue
conn.Open()
cmd.ExecuteNonQuery()
result = System.Convert.ToBoolean(retval.Value)
conn.Close()
End Using
Return result
End Function
If you're strictly interested in the return value and your Stored Procedure isn't performing any other use, then convert it to a simple select statement (or function). Your use of ExecuteScalar would work in that case.
Please try using SELECT 1 and SELECT 0 instead of RETURN statement
Hope that helps,

Resources