How do you use sp_getProcedureColumns()? - advantage-database-server

How do you use sp_getProcedureColumns()?
I cannot find any documentation for it.
Thanks,
Howard

I am unsure why that system procedure is not documented. However, I believe it uses the same syntax as sp_GetColumns. For example,
execute procedure sp_getProcedureColumns(null, null, 'myAEP', null );
And based on a comment in another question, you might also be interested in AdsCommand.DeriveParameters. Here is an example:
AdsCommand cmd = conn.CreateCommand();
cmd.CommandText = "SomeProcedure";
cmd.CommandType = CommandType.StoredProcedure;
cmd.DeriveParameters();
foreach ( AdsParameter p in cmd.Parameters )
Console.WriteLine( "{0}, {1}, {2}", p.ParameterName, p.DbType.ToString(),
p.Direction.ToString() );

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.

Asp.net Transaction with foreach loop

I am trying to save one Gridview with two checkbox in database with Asp.net Transaction , I am Getting Error when same condition come
SqlCommand cmd = new SqlCommand("procedure", con);
SqlCommand cmd1 = new SqlCommand("procedure1", con);
foreach (GridViewRow row in gvrecept.Rows)
{
if (cash.Checked){
cmd.Parameters.AddWithValue("#parameter", "value");
cmd.Transaction = trns;
}
else if (cheque.Checked)
{
cmd1.Parameters.AddWithValue("#parameter1", "value1");
cmd1.Transaction = trns;
}
}
int i = cmd1.ExecuteNonQuery();
int j = cmd.ExecuteNonQuery();
if (i > 0 && j > 0 )
{
trns.Commit();
}
As explained in my comment above you need to change something:
The trns should be added outside the loop just one time together with the setting to CommandType = CommandType.StoredProcedure and the creation of the two commands.
Inside the loop you should execute the command at each loop for each row you traverse. Also it is not clear if the two commands are mutually exclusive. I mean, if you have two checkboxes set then you should execute both commands but not if you don't have the matching checkbox set. If this is the case you need to use two separate ifs not an else if.
Notice that inside the loop you can simply change the value of the parameter before executing the command. This will be a smaller optimization but nevertheless it is simpler than creating the command or clearing the parameter collection at each loop.
Finally the commit of the Transaction should be done outside the loop when you have completed the insertion. If you have an error then an exception occurs and the Commit is skipped.
Final note. It is not clear why you need two commands at all. In the code above you use always the same StoredProcedure but passing different values. If this is the case then one command will do just fine.
SqlCommand cmd = new SqlCommand("procedure1", con);
cmd.Transaction = trns;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#parameter", SqlDbType.NVarChar);
SqlCommand cmd1 = new SqlCommand("procedure1", con);
cmd1.Transaction = trns;
cmd1.CommandType = CommandType.StoredProcedure;
cmd1.Parameters.Add("#parameter1", SqlDbType.NVarChar);
foreach (GridViewRow row in gvrecept.Rows)
{
if (cash.Checked)
{
cmd.Parameters["#parameter"].Value = "value";
cmd.ExecuteNonQuery();
}
if (cheque.Checked)
{
cmd.Parameters["#parameter1"].Value = "value1";
cmd1.ExecuteNonQuery();
}
}
trns.Commit();

Change stored proc to inline sql

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.

How to use having() in tableGateway in ZF2

How to use having() clause in ZF2?
There is almost no examples on the web how to prepare correct select object with having.
I have query like:
SELECT root_schema_id as `schema_id`
FROM `standard_specific_root_schemas`
WHERE `vehicle_id` IN (".implode(",",$vehiclesIds).")
GROUP BY `schema_id`, rootSubGroup_id HAVING count(*)=".$noOfVehicles
And I'm trying to run it in ZF2:
public function getVehicleWithinCommonRootSubgroupInSpecific($vehiclesIds)
{
$where = new Where();
$where->in('vehicle_id', $vehiclesIds);
$having = new Having('count(*) = '.count($vehiclesIds));
$rowset = $this->tableGateway->select(function (Select $select) use ($where, $having) {
$select
->where($where)
->having($having);
});
if (!$rowset) {
throw new \Exception("Could not find schemas for group $groupId");
}
return $rowset;
}
Of course that part in ZF2 is not finished yet as I wanted to check if it's working first.
I've tried few ways of providing params to having method but everything generates errors.
Help please, I'm desperate...
I cannot test your query, but can try and reproduce the query you need.
I adjusted the having to use ->expression() instead of a variable via the construct.
I also added the group statement.
To view the query I added a var_dump:
$where = new \Zend\Db\Sql\Where();
$where->in('vehicle_id', $vehiclesIds);
$having = new \Zend\Db\Sql\Having();
$having->expression('count(*) = ?', count($vehiclesIds));
$rowset = $this->tableGateway->select(function (\Zend\Db\Sql\Select $select) use ($where, $having) {
$select
->where($where)
->group(array('schema_id', 'rootSubGroup_id'))
->having($having);
var_dump( $select->getSqlString() );
});
Let me know if this helps.
To circumvent the error mentioned in the comments you would have to do something like below:
$sql = $this->tableGateway->getSql();
$select = $sql->select();
$where = new \Zend\Db\Sql\Where();
$where->in('vehicle_id', $vehiclesIds);
$having = new \Zend\Db\Sql\Having();
$having->expression('count(*) = ?', count($vehiclesIds));
$select
->where($where)
->group(array('schema_id', 'rootSubGroup_id'))
->having($having);
$preparedQuery = $sql->prepareStatementForSqlObject($select);
var_dump( $preparedQuery->getSql() );
However, if I'm right, the tableGateway does this for you so the error should go away once you start using the select to query the database.
Also, you can use the above to do that too, just replace this:
$preparedQuery = $sql->prepareStatementForSqlObject($select);
var_dump( $preparedQuery->getSql() );
With:
$this->tableGateway->selectWith($select);

sp_getProcedureColumns

I have tried to pass in the proc name into procedureNamePattern and the procedure seems to return all the metadata for all the procedures. I pass in a empty string and I get the same results.
The following is the code used:
using (AdsCommand command = new AdsCommand { CommandText = "sp_getProcedureColumns",
Connection = connection,
CommandType = CommandType.StoredProcedure })
{
AdsParameter param = new AdsParameter("#procedureNamePattern", DbType.String) {
Direction = ParameterDirection.Input, Value = originalProcedureName };
command.Parameters.Add(param);
AdsParameter param0 = new AdsParameter("#catalog", DbType.String) {
Direction = ParameterDirection.Input, Value = null };
command.Parameters.Add(param0);
AdsParameter param1 = new AdsParameter("#schemaPattern", DbType.String) {
Direction = ParameterDirection.Input, Value = null };
command.Parameters.Add(param1);
AdsParameter param2 = new AdsParameter("#columnNamePattern", DbType.String) {
Direction = ParameterDirection.Input, Value = null };
command.Parameters.Add(param2);
With stored procedures, you can use the DeriveParameters method. That might make it simpler. The following is an example:
AdsCommand cmd = conn.CreateCommand();
cmd.CommandText = "sp_getProcedureColumns";
cmd.CommandType = CommandType.StoredProcedure;
cmd.DeriveParameters();
cmd.Parameters["ProcedureNamePattern"].Value = "MyProcName";
AdsDataReader rdr = cmd.ExecuteReader();
If you do not call the DeriveParameters method, then the underlying SQL statement that is generated is produced directly from the provided parameters in the given order. That means you would need to provide the parameters in the order to match the procedure definition. In this case, the ProcedureNamePattern parameter needs to be 3rd. If you change the order of the cmd.Parameter.Add() calls, then your original example should work.

Resources