Change stored proc to inline sql - stored-procedures

I have the following classic asp working, calling a stored proc in the database. I would like to convert it over so instead of calling the stored proc it passes in the sql, adds the prams then executes it.
I tried all sorts of things and can't get it working.
Can someone convert this example?
Also it seems difficult to get reasonable error messages when passing in sql with params. Is there a way to see traces of this call so we can have some idea what is causing the problem?
Set cmd = server.createobject("ADODB.Command")
cmd.ActiveConnection = theDatabase
cmd.CommandType = adCmdStoredProc
cmd.commandText = "AddResponse"
cmd.Parameters("#id") = id
cmd.Parameters("#pc") = pc
cmd.Parameters("#idDate") = now
cmd.Execute , , adExecuteNoRecords
set cmd = Nothing
Stored Procedure definition
ALTER PROCEDURE [dbo].[AddResponse] #id NVARCHAR(12), #pc NVARCHAR(12), #idDate datetime
AS
BEGIN
SET NOCOUNT ON;
select * from EmailResponse
if not exists (SELECT id, projectCode FROM EmailResponse WHERE id = #id and projectCode = #pc)
begin
INSERT INTO EmailResponse (id, projectCode, dateEntered) VALUEs(#id, #pc, #idDate)
end
END
EDIT:
Here are my answers to everyone.
Wow stackoverflow is great because of everyone like yourselves
who spend a little time helping others.
the select * was a mistake
I have to maintain and convert some older asp code over to using stored procs.
Stored proc are the way to go "most" of the time.
For various reasons sometimes it is better to have the sql in the code.
(quick testing and development, no access to the database, etc.)
So I need to know how to handle both ways.
cmd.Parameters.Refresh
My code works fine without this call.
It is really necessary?
Reading what it is supposed to do was not a lot of help why I need to use it
Understanding types is critical for all types of programming.
This was exactly what I was asking for and more.
Carl Prothman - Data Type Mapping
Thanks for this!
I was also wondering how to set a record set object even though I forgot to ask. Thanks for this too!
set rs = server.createObject ("adodb.recordset")
rs =- cmd.Execute
I got all three working.
For anyone interested here is working and tested code to show all three approaches.
' Stored proc example
' ------------------------------------------
dim theDatabase, cmd, id, pc
theDatabase = "Driver={SQL Server}; Server=10.10.10.10,1433; Database=Test; uid=TestUser; pwd=TestPass;"
id = cleanInt(request.querystring("id"))
pc = sqlSafe(clean(request.querystring("pc")))
if pc<>"" and id<>"" then
Set cmd = server.createobject("ADODB.Command")
cmd.ActiveConnection = theDatabase
cmd.CommandType = adCmdStoredProc
cmd.commandText = "AddResponse"
cmd.Parameters("#id") = id
cmd.Parameters("#pc") = pc
cmd.Parameters("#idDate") = now
cmd.Execute , , adExecuteNoRecords
set cmd = Nothing
end if
' Inline SQl with ? example
' ------------------------------------------
dim theDatabase, cmd, id, pc
theDatabase = "Driver={SQL Server}; Server=10.10.10.10,1433; Database=Test; uid=TestUser; pwd=TestPass;"
id = cleanInt(request.querystring("id"))
pc = sqlSafe(clean(request.querystring("pc")))
if pc<>"" and id<>"" then
Set cmd = server.createobject("ADODB.Command")
cmd.ActiveConnection = theDatabase
cmd.CommandType = adCmdText
cmd.CommandText = _
"if not exists (SELECT id, projectCode FROM EmailResponse WHERE id = ? and projectCode = ?)" &_
"begin INSERT INTO EmailResponse (id, projectCode, dateEntered) VALUEs(?, ?, ?) end "
cmd.Parameters.Append cmd.CreateParameter("#id", adInteger, adParamInput, , id)
cmd.Parameters.Append cmd.CreateParameter("#pc", adVarchar, adParamInput, 12, pc)
cmd.Parameters.Append cmd.CreateParameter("#id2", adInteger, adParamInput, , id)
cmd.Parameters.Append cmd.CreateParameter("#pc2", adVarchar, adParamInput, 12, pc)
cmd.Parameters.Append cmd.CreateParameter("#idDate", adDBTimeStamp, adParamInput, -1, now)
cmd.Execute , , adExecuteNoRecords
set cmd = Nothing
end if
' Inline SQl with # example
' ------------------------------------------
dim theDatabase, cmd, sql, id, pc
theDatabase = "Driver={SQL Server}; Server=10.10.10.10,1433; Database=Test; uid=TestUser; pwd=TestPass;"
id = cleanInt(request.querystring("id"))
pc = sqlSafe(clean(request.querystring("pc")))
if pc<>"" and id<>"" then
Set cmd = server.createobject("ADODB.Command")
sql = ""
sql = sql & "SET NOCOUNT ON;" & vbCrLf
sql = sql & "DECLARE #id NVARCHAR(12)" & vbCrLf
sql = sql & "DECLARE #pc NVARCHAR(12)" & vbCrLf
sql = sql & "DECLARE #idDate DATETIME" & vbCrLf
sql = sql & "SELECT #id = ?, #pc = ?, #idDate = ?" & vbCrLf
sql = sql & "IF NOT EXISTS (SELECT id, projectCode FROM EmailResponse WHERE id = #id and projectCode = #pc)" & vbCrLf
sql = sql & "INSERT INTO EmailResponse (id, projectCode, dateEntered) VALUEs(#id, #pc, #idDate);"
cmd.ActiveConnection = theDatabase
cmd.CommandType = adCmdText
cmd.CommandText = sql
cmd.Prepared = true
cmd.Parameters.Append cmd.CreateParameter("#id", adInteger, adParamInput, , id)
cmd.Parameters.Append cmd.CreateParameter("#pc", adVarchar, adParamInput, 12, pc)
cmd.Parameters.Append cmd.CreateParameter("#idDate", adDBTimeStamp, adParamInput, -1, now)
cmd.Execute , , adExecuteNoRecords
set cmd = Nothing
end if
Thanks everyone.

There is nothing wrong with the above code you are just missing using the Refresh() method of the Parameters collection before trying to set the named parameter values.
Set cmd = server.createobject("ADODB.Command")
With
.ActiveConnection = theDatabase
.CommandType = adCmdStoredProc
.commandText = "AddResponse"
'Query the provider for the parameter details
Call .Parameters.Refresh()
.Parameters("#id") = id
.Parameters("#pc") = pc
.Parameters("#idDate") = now
Call .Execute(, , adExecuteNoRecords)
End With
set cmd = Nothing
If you don't want to use this method the parameter definitions have to come from somewhere so the other option is to define them yourself to reflect the definitions of the stored procedure.
Set cmd = server.createobject("ADODB.Command")
With cmd
.ActiveConnection = theDatabase
.CommandType = adCmdStoredProc
.commandText = "AddResponse"
'Define parameters manually
Call .Parameters.Append(.CreateParameter("#id", adVarWChar, adParamInput, 12))
Call .Parameters.Append(.CreateParameter("#pc", adVarWChar, adParamInput, 12))
Call .Parameters.Append(.CreateParameter("#idDate", adDBTimeStamp, adParamInput, 8))
.Parameters("#id") = id
.Parameters("#pc") = pc
.Parameters("#idDate") = now
Call .Execute(, , adExecuteNoRecords)
End With
set cmd = Nothing
If you do go down the manual route a great resource for identifying what ADO DataTypeEnum constants to use is Carl Prothman - Data Type Mapping
Side-note: You have this line in your Stored Procedure;
select * from EmailResponse
Which expects to return a resultset but you specify adExecuteNoRecords in your ADODB.Command Execute() method which causes this to be ignored, if you do want to return it adjust the above to be;
Dim rs
...
With cmd
...
Set rs = .Execute()
End With
... is used to show where code is omitted
Needs pointing out that while #dimason approach (since removed, not sure why...) is sound it does over complicate things by adding two extra parameters when they are not needed, you can just declare the parameters inside the dynamic SQL and assign them to use those locally declared variables to run the statements instead.
Dim sql
sql = ""
sql = sql & "SET NOCOUNT ON;" & vbCrLf
sql = sql & "DECLARE #id NVARCHAR(12)" & vbCrLf
sql = sql & "DECLARE #pc NVARCHAR(12)" & vbCrLf
sql = sql & "DECLARE #idDate DATETIME" & vbCrLf
sql = sql & "SELECT #id = ?, #pc = ?, #idDate = ?" & vbCrLf
sql = sql & "SELECT * FROM EmailResponse;" & vbCrLf
sql = sql & "IF NOT EXISTS (SELECT id, projectCode FROM EmailResponse WHERE id = #id and projectCode = #pc)" & vbCrLf
sql = sql & "INSERT INTO EmailResponse (id, projectCode, dateEntered) VALUEs(#id, #pc, #idDate);"
Set cmd = server.createobject("ADODB.Command")
With cmd
.ActiveConnection = theDatabase
.CommandType = adCmdText
.CommandText = sql
.Prepared = true
.Parameters.Append cmd.CreateParameter("#id", adVarChar, adParamInput, 12, id)
.Parameters.Append cmd.CreateParameter("#pc", adVarChar, adParamInput, 12, pc)
.Parameters.Append cmd.CreateParameter("#idDate", adDBTimeStamp, adParamInput, 8, Now())
Set rsOut = .Execute()
End With
Set cmd = Nothing
Useful Links
Answer to ADODB.Parameters error '800a0e7c' Parameter object is improperly defined. Inconsistent or incomplete information was provided - Some information about manually defining a Parameter to avoid errors.

To switch from a stored procedure to inline SQL, you need to change
cmd.CommandType = adCmdStoredProc
to
cmd.CommandType = adCmdText
Then you need to add the query to the command text property:
cmd.CommandText = "SELECT * FROM Orders WHERE CustomerID = ?"
The above line was derived from the Command Object Parameters example on MSDN.

Related

Is if...exists supported in Snowflake stored procedures?

I have written a stored procedure which will be called from python. The stored procedure needs to insert the variant data into my table if the id doesn't exist or update the existing variant data where there is a match for the id. The id will be passed the way the variant data is, but for now I am just trying to get it working with a hardcoded id. The stored procedure gets called successfully from python, but then nothing gets inserted or updated in the stored procedure and the stored procedure doesn't give me an error. I am not sure if I am doing something wrong or the...
if exists (select * from my_database_table where my_variant_data:id::varchar = '123456')
... part is being ignored because it isn't supported. I haven't been able to find anything in the documentation to prove or disprove this. Does anyone know?
create or replace procedure my_stored_procedure("variant_data" variant)
returns string
language javascript
strict
execute as owner
as
$$
var insert_update_query = `
if exists (select * from my_database_table where my_variant_data:id::varchar = '123456')
begin
update my_database_table SET my_variant_data = parse_json(:1)) WHERE my_variant_data:id::varchar = '123456'
end
else
begin
insert into my_database_table(my_variant_data) select (parse_json(:1));
end
`
var result = "";
try {
var sql_insert_update_query = snowflake.createStatement({
sqlText: insert_update_query
});
var insert_update_query_result = sql_insert_update_query.execute();
result += "\n Query succeeded";
} catch (err) {
result += "\n Query failed failed: " + err.code + "\n State: " + err.state;
result += "\n Message: " + err.message;
result += "\n Stack Trace:\n" + err.stackTraceTxt;
}
return result;
$$
;
I have tested the insert and update parts of the query in the stored procedure individually and they work fine.
Insert - works as expected.
create or replace procedure my_stored_procedure("variant_data" variant)
returns string
language javascript
strict
execute as owner
as
$$
var sql_command = "insert into my_database_table(my_variant_data) select (parse_json(:1));";
var sql = snowflake.createStatement( {sqlText: sql_command, binds:[JSON.stringify(variant_data)]});
var resultSet = sql.execute();
return sql_command;
$$
;
Update - works as expected.
create or replace procedure my_stored_procedure("variant_data" variant)
returns string
language javascript
strict
execute as owner
as
$$
var sql_command = "UPDATE my_database_table SET my_variant_data = parse_json(:1)) WHERE my_variant_data:id::varchar = '123456'";
var sql = snowflake.createStatement( {sqlText: sql_command, binds:[JSON.stringify(variant_data)]});
var resultSet = sql.execute();
$$
;
Given the CODE executed needs to be valid runs on the console SQL, which this if is not, and it is fundamentally a MERGE command I would suggest flipping the code into a MERGE:
MERGE INTO my_database_table USING my_database_table
ON my_variant_data:id::varchar = '123456'
WHEN MATCHED THEN UPDATE SET my_variant_data = parse_json(:1))
WHEN NOT MATCHED THEN INSERT (my_variant_data) VALUES (parse_json(:1));
otherwise if you are want it in SP space, then I would be inclinded to break the code into a SELECT x INTO varaible FROM blar pattern and then have the IF be in SP and pick between the two blocks of SQL to run. But given it's just a merge, I would again still, do a merge.

How to get data from a stored Procedure that joins 3 tables and takes 3 different Parameters asp.net MVC

I have to create something that executes a stored Procedure, and depending on the parameters passed it will show data from different Tables. I am using EF model.
The Parameters are #Username, #FamilyID, #CategoryID
If you run it with Just #Username it will retrieve Families
If you run it with #Username and #FamilyID it will retrieve Categories
If you run it with all parameters it will return Report Names
I'm very new to ASP.Net, and I was seeking for help to display the results of this stored procedure. I have succeeded on executing a stored procedure that uses one single table, but unfortunately haven't with this specific one...
SP
ALTER Procedure [Report].[Rep_ReportListforUser]
#UserName varchar(50),
#FamilyId int = 0 ,
#CategoryID int = 0
as
Set nocount on
If #FamilyId = 0
Begin
Select RF.ID FamilyID,RF.Family FamilyName,1 Allowed
from Rep_ReportFamilies RF
End
Else If #CategoryID = 0
--Categories
Begin
Select Cat.Id CategoryID , Cat.Category ,Case when UF.ReportFamilyId is null then 0 else 1 end Allowed
from dbo.Rep_ReportFamilies RF Left Join dbo.Rep_User_Family UF On RF.ID = UF.ReportFamilyID
Join dbo.Rep_ReportCategories Cat on Cat.FamilyID = RF.ID
where UserId = (Select UserID from Report.Users where Username = #UserName)
and RF.ID = #FamilyID
End
Else
Begin
Select RL.ReportID , ReportDescription ReportName, Case when RU.Userid is null then 0 else 1 end Allowed
from dbo.Rep_ReportNames RL
Left Join dbo.Rep_Report_Users RU on RU.ReportId = RL.ReportId
Where RL.CategoryID = #CategoryID and
RU.userid = (Select userid from Report.Users
where Username = #UserName)
Order by ReportDescription
end
Code
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter ("#UserName","john"),
new SqlParameter ("#FamilyId",10),
new SqlParameter ("#CategoryID",24),
};
var families = context.Database.SqlQuery<Rep_ReportFamilies>("[Report].Rep_ReportListforUser #Family");
var username = context.Database.SqlQuery<Rep_ReportNames>("[Report].Rep_ReportListforUser #UserName");
var category = context.Database.SqlQuery<Rep_ReportNames>("[Report].Rep_ReportListforUser #CategoryID");
return View();
}
Hope Someone can Help
Happy Coding!
Need to update your code the following way.
Updated Code.
// If you run it with Just #Username it will retrieve Families
var families = context.Database.SqlQuery<Rep_ReportFamilies>("EXEC [Report].Rep_ReportListforUser #UserName, #FamilyId, #CategoryID ",
new SqlParameter ("#UserName","john"),
new SqlParameter ("#FamilyId",0),
new SqlParameter ("#CategoryID",0);
//If you run it with #Username and #FamilyID it will retrieve Categories
var username = context.Database.SqlQuery<Rep_ReportFamilies>("EXEC [Report].Rep_ReportListforUser #UserName, #FamilyId, #CategoryID ",
new SqlParameter ("#UserName","john"),
new SqlParameter ("#FamilyId",10),
new SqlParameter ("#CategoryID",0);
//If you run it with all parameters it will return Report Names
var category = context.Database.SqlQuery<Rep_ReportFamilies>("EXEC [Report].Rep_ReportListforUser #UserName, #FamilyId, #CategoryID ",
new SqlParameter ("#UserName","john"),
new SqlParameter ("#FamilyId",10),
new SqlParameter ("#CategoryID",24);

Padright in combo box displaymember

I have the following 2 segments of code which populates my combo box but the First Name column obviously is a squiggly one since surnames are various lengths. How could I use something like padright to align the first name column? I have other code using a binding source method but it seems a bit long winded & I'd like to improve on that for all the combos I still have to create.
If RadioButton1.Checked Then
strSQL = "select *, Surname + ' ' + First_Name as Name from tblCompetitors order by Surname, First_Name"
cboData()
End If
Public Sub cboData()
Dim dt As New DataTable
Using conn As New SqlClient.SqlConnection(connString)
If conn.State = ConnectionState.Closed Then
conn.Open()
End If
Using com As SqlCommand = New SqlCommand(strSQL, conn)
Dim dr As SqlDataReader = com.ExecuteReader()
'Dim dt As DataTable = New DataTable
dt.Load(dr)
' as an example set the ValueMember and DisplayMember'
cboFindCompetitor.ValueMember = "Competitor_Idx"
cboFindCompetitor.DisplayMember = "Name"
'Set combobox’s datasource to datatable dt
cboFindCompetitor.DataSource = dt
End Using 'com
End Using 'conn
cboFindCompetitor.SelectedIndex = -1
End Sub
After some fiddling I came up with this solution. It works well on my machine with +- 3000 records in the table
Private Sub RadioButton1_CheckedChanged(sender As Object, e As EventArgs) Handles RadioButton1.CheckedChanged
If RadioButton1.Checked Then
strSQL = "select Competitor_Idx, Surname as Value1, First_Name as Value2 from tblCompetitors order by Value1, Value2"
cboData(25)
End If
End Sub
Public Sub cboData(z As Integer)
Dim dt As New DataTable
Using conn As New SqlClient.SqlConnection(connString)
If conn.State = ConnectionState.Closed Then
conn.Open()
End If
Using com As SqlCommand = New SqlCommand(strSQL, conn)
Dim dr As SqlDataReader = com.ExecuteReader()
'Dim dt As DataTable = New DataTable
dt.Load(dr)
dt.Columns.Add("Name", GetType(String))
' as an example set the ValueMember and DisplayMember'
cboFindCompetitor.ValueMember = "Competitor_Idx"
cboFindCompetitor.DisplayMember = "Name"
For Each row In dt.Rows
row.item("Name") = row.item("Value1").padright(z) + row.item("Value2")
Next
'Set combobox’s datasource to datatable dt
cboFindCompetitor.DataSource = dt
End Using 'com
End Using 'conn
cboFindCompetitor.SelectedIndex = -1

How to execute a dynamic stored procedure that return a table in vb6 recordset and assign Datasource to a spreadgrid

I wrote a dynamic procedure than populate the columns and then use Pivot to show the data.
How to execute this procedure from vb6 and return the content as datasource.
You can use ADO for this, you will need to add a reference to Microsoft ActiveX Data Ojects. The code as I remember (long time since vb6) is something like
Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Set conn = New ADODB.Connection
Set rs = New ADODB.Recordset
Dim strConn As String
Dim strSQL As String
Dim strCol1 As String
Dim strCol2 As String
strConn = "[YOUR CONNECTION SRING]" '(see www.connectionstrings.com for help)
conn.Open connStr
strSQL = "[YOUR SQL QUERY]" '(IE. Proc name)
rs.Open strSQL, conn, adOpenStatic, adLockOptimistic
Do While Not rs.EOF
strCol1 = rs.Fields("Col1Name")
strCol1 = rs.Fields("Col2Name")
rs.MoveNext
Loop
If rs.State = adStateOpen Then rs.Close
Set rs = Nothing
If conn.State = adStateOpen Then conn.Close
Set conn = Nothing

Getting a value from one table to pull up values from another table

I am trying to lookup an employeeid from one table based on the windows login name, and use this employeeid to get values from another table to add them up. So, for Bill, the employeeid is 1 in tblEmployees. I sum all noofhours in tblTimeAvailable where employeeid equals 1 and display this on my webpage. It's not working. I can't figure out how to search the second table by the employeeid found in the first table. (I'm rewriting code because of sql injection.)
Dim windowsLoginName As System.String = HttpContext.Current.User.Identity.Name 'System.Security.Principal.WindowsIdentity.GetCurrent().Name
Dim split As String() = Nothing
Dim vname As String
'Get network login name (name only)
split = windowsLoginName.Split("\".ToCharArray)
vname = split(1)
Dim Connection As String = "Data Source=WillSQL\ict2;Initial Catalog=TimeSQL;Integrated Security=SSPI"
Using con As New SqlConnection(Connection)
Dim sqlemp As String = "SELECT EmployeeID FROM tblEmployees where login = #loginname"
Dim command As New SqlCommand(sqlemp, con)
con.Open()
rve = cmde.Parameters.Add(New SqlParameter With {.ParameterName = "#loginname", .SqlDbType = SqlDbType.NVarChar, .Value = vname})
End Using
When I look at value of rve, it's giving me #loginname and not the employeeid. FYI - there will always be only one row in tblEmployees because each Windows login name is unique.
'Get Sick Time
Using con As New SqlConnection(Connection)
Dim sqls1 As String = "Select SUM(NoofHours) as Total from tblTimeAvailable where workcode = 1 and EmployeeID = #employeeid"
Dim command As New SqlCommand(sqls1, con)
con.Open()
rvsa = cmde.Parameters.Add(New SqlParameter With {.ParameterName = "#employeeid", .SqlDbType = SqlDbType.NVarChar, .Value = rve})
End Using
' If the sum equals 0, show 0 on webpage. If another value, show value.
If IsDBNull(rvsa) Then
rvsa = 0
TextBoxsa.Text = 0
Else
TextBoxsa.Text = rvsa.ToString
End If
I appreciate any help you can give me!
You are never executing the command. After setting the values of the various parameters, you need to then call one of the execute methods on the SqlCommand object. In this case, since you are just reading a single value from a single row, you can simply use the ExecuteScalar method:
rve = command.ExecuteScalar()

Resources