Using VB.net to alter Stored Parameters - asp.net

I am having an issue modifying a stored procedure variable with VB.net. I have found many posts on the topic that made it seem like a simple .AddWithValue solution but I keep ending up with a the following exception:
The IListSource does not contain any data sources.
The stored procedure is a Dynamic Pivot table that works great with a static value for #dcs
CREATE PROCEDURE [dbo].[dcspull]
as
DECLARE #cols AS NVARCHAR(MAX),
#colsNull AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#dcs AS INT
select #cols = STUFF((SELECT ',' + QUOTENAME(FirstName)
FROM[Training Data]
WHERE DataCenterID = #dcs
GROUP by FirstName
ORDER by FirstName
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
select #colsNull = STUFF((SELECT ', coalesce(' + QUOTENAME(FirstName)+''''')
AS '+QUOTENAME(+FirstName)
FROM [Training Data]
WHERE DataCenterID = #dcs
GROUP by FirstName
ORDER by FirstName
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #query = 'SELECT Topic, ' + #colsNull + '
FROM
(SELECT FirstName, Topic, Level
FROM [Training Data]) x
PIVOT
(MAX(Level)
FOR FirstName IN (' + #cols + ')) p'
execute(#query)
The only value I am trying to change via VB.Net is #dcs. When #dcs is set statically the Gridview populates as expected, but as soon as I try to pass a value to the parameter it breaks.
Dim SQLCon As String = ConfigurationManager.ConnectionStrings("tCString").ToString
Dim DBConnSQL As New SqlConnection(SQLCon)
Dim da As New SqlDataAdapter
Dim ds As New DataSet
DBConnSQL.Open()
Dim dbcheckone As New SqlCommand("dcspull", DBConnSQL)
dbcheckone.parameters.addwithvalue("#dcs", Convert.ToInt64(DropDownList1.Text))
da.SelectCommand = dbcheckone
da.Fill(ds)
GridView1.DataSource = ds
GridView1.DataBind()
I am fairly new to stored procedures and am assuming this is something I just don't understand about the relationship.

First, I don't see any parameters in your stored procedure. They should come before AS.
Sample Create SP:
CREATE PROCEDURE HumanResources.uspGetEmployeesTest2
#LastName nvarchar(50),
#FirstName nvarchar(50)
AS
Now, when you add those parameters it should work under these conditions:
You need to set command Type
dbcheckone.CommandType = CommandType.StoredProcedure
Even though you don't use other parameters during your call, your procedure signature and procedure itself don't match. You can't omit non-optional parameters. So you need to list every parameter
dbcheckone.parameters.addwithvalue("#cols"...
dbcheckone.parameters.addwithvalue("#colsNull"...
dbcheckone.parameters.addwithvalue("#query"...
dbcheckone.parameters.addwithvalue("#dcs", Convert.ToInt32(DropDownList1.Text))
About the last line here - you set it in your code to Convert.ToInt64 but your parameter is int, therefore it should match int32.

Related

How to store more than 8000 characters and assign large concatenated string in SQL Server 2008?

I am trying to concatenate the large number of id'd and to update the status of all id's.
For example:
aclid in (4604019,4604018,4604017,4604016,4604015,4604014,4604013,4604012,4604011,4604010,4604009,4604008,4604007,4604006,4604005,4604004,4604003,4604002,4604001,4604000,4603999,4603998,4603997,4603996,4603995,4603994,4603993,4603992,4603991,4603990,4603989,4603988)`
Please check my stored procedure:
ALTER PROCEDURE [dbo].[VT_ACLReportChangeStatus]
(#ChangeStatus nvarchar(50) = null,
#ACLId nvarchar(max))
AS
/* Exec VT_ACLReportChangeStatus 'Complete','4599473,4599472,4599471,4599469,4599468' */
BEGIN
UPDATE VT_ACLReport
SET Status = #ChangeStatus
WHERE ACLId IN (SELECT * FROM SplitDelimiterString(#ACLId,','))
END
Please check my code behind:
ACLId = ACLId.ToString().Trim(',');
using (SqlConnection con = new SqlConnection(cs))
{
cmd = new SqlCommand("VT_ACLReportChangeStatus", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandTimeout = 3600;
cmd.Parameters.Add(new SqlParameter("#ACLId", SqlDbType.NVarChar,-1));
cmd.Parameters.Add(new SqlParameter("#ChangeStatus", SqlDbType.NVarChar, 50));
cmd.Parameters["#ACLId"].Value = ACLId;
cmd.Parameters["#ChangeStatus"].Value = ddlChangeStatus.SelectedItem.Text.ToString();
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
AclId column data type is bigint identity.
Please can you help me in concatenating large string and to update all rows whose aclid is present.
I would suggest, create one user defined table type in sql and one class in sourecode with your respective data. You can pass object of this class to sql and in your SP you can use join between main table and this table(which is received as input parameter) to update data.
Thanks all of you for your answers.. Actually it was silly mistake,while calling splitting function in Stored procedure. In function it was varchar(8000). :) solved it.
ALTER FUNCTION [dbo].[SplitDelimiterString] (#StringWithDelimiter VARCHAR(max), #Delimiter VARCHAR(max))
RETURNS #ItemTable TABLE (Item VARCHAR(max))
AS
BEGIN
DECLARE #StartingPosition INT;
DECLARE #ItemInString VARCHAR(max);
SELECT #StartingPosition = 1;
--Return if string is null or empty
IF LEN(#StringWithDelimiter) = 0 OR #StringWithDelimiter IS NULL RETURN;
WHILE #StartingPosition > 0
BEGIN
--Get starting index of delimiter .. If string
--doesn't contain any delimiter than it will returl 0
SET #StartingPosition = CHARINDEX(#Delimiter,#StringWithDelimiter);
--Get item from string
IF #StartingPosition > 0
SET #ItemInString = SUBSTRING(#StringWithDelimiter,0,#StartingPosition)
ELSE
SET #ItemInString = #StringWithDelimiter;
--If item isn't empty than add to return table
IF( LEN(#ItemInString) > 0)
INSERT INTO #ItemTable(Item) VALUES (#ItemInString);
--Remove inserted item from string
SET #StringWithDelimiter = SUBSTRING(#StringWithDelimiter,#StartingPosition +
LEN(#Delimiter),LEN(#StringWithDelimiter) - #StartingPosition)
--Break loop if string is empty
IF LEN(#StringWithDelimiter) = 0 BREAK;
END
RETURN
END

Dynamic query as a parameter in stored procedure and SQL Injection

I have the following stored procedure (modified for this post):
ALTER PROCEDURE [dbo].[SEL_ARTICLE](
#FILTER VARCHAR(8000) = ''
) AS
BEGIN
DECLARE #SQLQuery varchar(8000);
SET #SQLQuery = 'SELECT DISTINCT ArticleNo, desc, ...
FROM Article INNER JOIN
...
{0}
ORDER BY ArticleNo, ...';
SET #SQLQuery = REPLACE(#SQLQuery, '{0}', #FILTER);
EXEC(#SQLQuery);
END
I call this proc in my prog like this:
Public Function get_Article(ByVal strFilter As String) As DataTable
Dim tblData As New DataTable
Dim par As SqlParameter = New SqlParameter("#FILTER", SqlDbType.VarChar)
par.Value = strFilter
Load_Data("SEL_ARTICLE", tblData, par) 'SqlCommand used
Return tblData
End Function
The value of the parameter strFilter is dynamic (Fields, values) depending on what we search. Here is an example:
" AND ((Article = [input from User]) OR (Description LIKE '%[input from User]%'))"
The user must be able to enter the character ' (word in French) it is why I replace it server-side like this:
strFilter &= String.Format(" AND ((Article = {0}) OR (description LIKE '%{1}%'))", strArticleNo, strArticleName.Replace("'", "''"))
I prevent the user to enter the following characters: <,>,{,},;
Now my question:
Is this code safe against SQL injection attacks ?
Thank you!

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

Stored Procedure Returns zero results

I developed a search page containing a textbox control for entering a number and button to display the respective results in a Gridview. The page functions off a stored procedure. The sql query returns the expected results when ran via SQL Server Manager when I manually type in the number, but when used in my stored procedure, I get zero results.
This is the code behind the button-event handler:
Dim ds As New DataSet()
Using connection As New SqlConnection(ConfigurationManager.ConnectionStrings("ShipperNotificationConnectionString1").ToString())
Using command As New SqlCommand()
command.CommandType = CommandType.StoredProcedure
command.CommandText = "getPON"
command.Connection = connection
command.Parameters.AddWithValue("#PON", txtPON.Text)
connection.Open()
Dim a As New SqlDataAdapter(command)
a.Fill(ds)
End Using
End Using
gvPON.DataSource = ds
gvPON.DataBind()
...The following is the stored procedure:
ALTER PROCEDURE [dbo].[getPON]
(
#PON varchar
)
AS
BEGIN
SELECT SupplierCompany.company_name, SupplierCompany.Address1, SupplierCompany.Address2, SupplierCompany.City, SupplierCompany.State,
SupplierCompany.Zip, Shipment_Po.PONumber, Shipment.TotalWeight, Shipment.NoOfPallets, Shipment.PalletIdentical
FROM SupplierCompany INNER JOIN
Shipment ON SupplierCompany.Company_guid = Shipment.Company_Guid INNER JOIN
Shipment_Po ON Shipment.Shipment_Guid = Shipment_Po.Shipment_guid
WHERE Shipment_Po.PONumber = '''+ #PON +'''
END
...Could someone please provide some direction?
The problem is the stored procedure. The expression:
WHERE Shipment_Po.PONumber = '''+ #PON +'''
Is not doing what you think. It is doing the following comparison:
WHERE Shipment_Po.PONumber = '+#PON+'
Or something like that. In other words, you are mixing dynamic SQL expressions with regular SQL. Try doing:
WHERE Shipment_Po.PONumber = #PON
If you are concerned about the cast to the right type:
WHERE Shipment_Po.PONumber = (case when isnumeric(#PON) = 1 then cast(#PON as int) end)

SQL SUM negative value not being returned

I have an SQL Query that looks like this -
CREATE PROCEDURE [dbo].[getMemberFundUnits]
-- Add the parameters for the stored procedure here
#member int,
#fundcode varchar(15),
#closingdate datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT (CASE WHEN SUM(units) IS Null THEN 0 ELSE SUM(units) END) As fundunits
FROM pe_minv
WHERE pmi_member = #member AND pmi_fund = #fundcode AND pmi_invested <= #closingdate
END
When I run the stored procedure like this -
DECLARE #return_value as float /*int*/
EXEC #return_value = [dbo].[getFundUnits]
#member = 9738,
#fundcode = N'58193',
#closingdate = N'07/21/2011'
SELECT 'Return Value' = #return_value
I get two results. The first is the correct one which is -0.0060 and the second #return_value which is 0
This is also the case when I call the stored procedure from my code, I get a 0 back instead of the -0.0060 that I want.
This is how I am calling the stored procedure from my code:
Dim ds As New DataSet()
Dim cmd As New SqlCommand("getMemberFundUnits", conn)
cmd.CommandType = CommandType.StoredProcedure
Dim p_pm_member As New SqlParameter("#member", SqlDbType.Int)
p_pm_member.Value = pm_member
cmd.Parameters.Add(p_pm_member)
Dim p_fund_code As New SqlParameter("#fundcode", SqlDbType.VarChar)
p_fund_code.Value = fund_code
cmd.Parameters.Add(p_fund_code)
Dim p_period_closing_date As New SqlParameter("#closingdate", SqlDbType.DateTime)
p_period_closing_date.Value = period_closing_date
cmd.Parameters.Add(p_period_closing_date)
Dim da As New SqlDataAdapter(cmd)
da.Fill(ds)
Does anyone have any ideas why this might be happening?
Thanks!
DECLARE #return_value as int
Your variable is defined as int. Int can't hold decimal values, so the return value is rounded. Try to declare your var as float.
List of SQL Server data types
The RETURN is always int so it is truncated inside the stored procedure.
As per MSDN
RETURN [ integer_expression ]
You need to use an OUTPUT parameter that is float:
CREATE PROC [dbo].[getFundUnits]
#member...,
#fundcode...',
#closingdate...,
#SummedValue float OUTPUT
AS
...
SELECT #SummedValue = (CASE WHEN SUM(nits) IS Null THEN 0 ELSE SUM(units) END) As fundunits
...
GO
And you call it as
DECLARE #return_value as float
EXEC [dbo].[getFundUnits]
#member = 9738,
#fundcode = N'58193',
#closingdate = N'07/21/2011',
#return_value OUTPUT
SELECT 'Return Value' = #return_value
RETURN is used (if at all) only for execution status usually: meaningful data is via output parameters or a resultset. I no longer use RETURN...
Try declaring the return value as Decimal with precision.
DECLARE #return_value as decimal(18,4)
Also, why are you filling a dataset for only returning one column. Use a sqldatareader and retrieve the values as decimal. Dataset is very resource intensive.

Resources