How to include several sql commands? - sqlcommand

With ASP.NET with C#, I am trying display numerous GridViews with different SQL commands. Because the SQL statements are long, I would like to include the variables instead of the actual statements, but I'm not sure exactly how to insert them in the SqlCommand method. Without the variable, the code appears as so
SqlCommand cmd = new SqlCommand("SELECT....; SELECT...." , myConn);
but instead of the actual statement, I'd like to replace the above sql statements with string variables like below...
string sqlVar1 = "SELECT.....";
string sqlVar2 = "SELECT....";
How do I incorporate the variables to the above code? Below does not work.
SqlCommand cmd = new SqlCommand(sqlVar1; sqlVar2, myConn);
Is there a punctuation I'm missing or perhaps additional code is required to recognize that I'm using variables instead of the actual sql statements?

You simple need to concatenate the strings:
SqlCommand cmd = new SqlCommand(sqlVar1 + ';' + sqlVar2, myConn);
If you have multipple commands - a better approach would be to use a StringBuilder to collect them and StringBuilder.ToString() as a first parameter for SqlCommand constructor:
StringBuilder sb = new StringBuilder();
sb.Append("SELECT .....;");
sb.Append("SELECT .....;");
SqlCommand cmd = new SqlCommand(sb.ToString(), myConn);
But the best approach is to set all your SELECT commands in a stored procedure and call that SP.

You need to concatenate your string values together before you pass them to the constructor:
SqlCommand cmd = new SqlCommand(String.Format("{0};{1}", sqlVar1, sqlVar2), myConn);

Related

Is there an alternative to using ResultSet of one statement as format string parameters to execute another statement

PostgreSQL 9.2, jdbc4, and the DBMS is through PgAdmin3.
I need to retrieve some resultset with a statement object which is a callable object with a stored function and then process the types through comparison of those resultset types. After I process them I hope to set some of them as format string arguments for another statement.
This is some pseudocode of sorts for what I want to accomplish. Essentially I want to iteratively add to batch and then do a batch update with a savepoint or rollback and commit those changes after executing that batch.
In addition there are some postgres in stored procedures as a string for jdbc related syntax I am uncertain of as far as using IS NULL, escaping quotes, requiring a semi-colon, etc.
String SQL = "UPDATE AdminBoundaries SET \"WIKI_URL\" = ?";
Statement stmt = conn.createStatement();
stmt.execute("CREATE OR REPLACE FUNCTION refcursorfunc() RETURNS refcursor AS '"
+ " DECLARE "
+ " mycurs refcursor; "
+ " BEGIN "
+ " OPEN mycurs FOR SELECT \"NAME_5\", \"NAME_4\", \"NAME_3\", \"NAME_2\", \"NAME_1\", \"NAME_0\", \"WIKI_URL\", \"LEVEL_DEPT\" FROM"
+ " AdminBoundaries WHERE \"WIKI_URL\" IN(SELECT \"WIKI_URL\" FROM AdminBoundaries"
+ " GROUP By \"WIKI_URL\" HAVING (count (\"WIKI_URL\") > 1)) ORDER BY \"WIKI_URL\";; "
+ " RETURN mycurs; "
+ " END;' language plpgsql");
conn.setAutoCommit(false);
CallableStatement funct = conn.prepareCall("{ ?, ?, ?, ?, ?, ?, ?,? = call refcursorfunc()}");
funct.registerOutParameter(1, java.sql.Types.VARCHAR);
funct.registerOutParameter(2, java.sql.Types.VARCHAR);
funct.registerOutParameter(3, java.sql.Types.VARCHAR);
funct.registerOutParameter(4, java.sql.Types.VARCHAR);
funct.registerOutParameter(5, java.sql.Types.VARCHAR);
funct.registerOutParameter(6, java.sql.Types.VARCHAR);
funct.registerOutParameter(7, java.sql.Types.VARCHAR);
funct.registerOutParameter(8, java.sql.Types.INTEGER);
funct.execute();
ResultSet results (ResultSet) funct.getObject(1);
while(results.next()){
String base_url = "http://127.0.0.1/mediawiki/index.php/";
String name0 = rs.getString("NAME_0");
String name1 = rs.getString("NAME_1");
String name2 = rs.getString("NAME_2");
String name3 = rs.getString("NAME_3");
String name4 = rs.getString("NAME_4");
String name5 = rs.getString("NAME_5");
String wiki_url = rs.getString("WIKI_URL");
int level = rs.getInt("LEVEL_DEPT");
}
PreparedStatement pstmt = null;
pstmt = conn.prepare(SQL, ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.HOLD_CURSORS_OVER_COMMIT, ResultSet.CONCUR_UPDATABLE);
if(wiki_url.equals(somestring)){
if(name1 == null){
if(level != 0){
pstmt.setString(1, somestring + name1);
pstmt.addBatch();
if(name2 == null ){
...etc.
}
}
//either executeUpdate or executeBatch
conn.commit()
pstmt.clearBatch()
conn.setAutoCommit(true);
}
Is it possible in this case to mix and match prepared statements, callable statements, or statements?
I know you can only have one resultset per statement open until you execute that statement, but how do I keep the resultset's type objects (i.e. getXXX and store it as some data type) to use on another statement if it closes?
This is for an application that will first use a select to retrieve data, then three updates. All three will be batch updates with varying parameters which will iterate through rows of a database, all on separate transactions with commits after each update. Each update will be a separate function.
I was originally thinking about using the resultset of one statement and then using updateXXX and updateRow, but I'm not entirely sure about the efficiency.

Google Cloud SQL + RETURN_GENERATED_KEYS

I've got a table in my Google Cloud SQL database with an auto-incrementing column.
How do I execute an INSERT query via google-apps-script/JDBC and get back the value for the newly incremented column?
For example, my column is named ticket_id. I want to INSERT and have the new ticket_id value be returned in the result set.
In other words, if I have the following structure, what would I need to modify or how, so that I can do something like rs = stmt.getGeneratedKeys();
var conn = Jdbc.getCloudSqlConnection("jdbc:google:rdbms:.......
var stmt = conn.createStatement();
//build my INSERT sql statement
var sql = "insert into ......
var rs = stmt.executeUpdate(sql);
I see that there is a JDBC statement class with a member called RETURN_GENERATED_KEYS but I have so far not been smart enough to figure out how to properly manipulate that and get what I need. Is RETURN_GENERATED_KEYS a constant, is it an attribute, or how can I make use of it?
It seems like the documentation with the Apps Script JDBC service is a bit lacking. I've created an internal task item for that. Thankfully, Apps Script JDBC API follows the Java JDBC API pretty closely. The key is to get the result set back using the stmt.getGeneratedKeys() call.
I built a sample table using the animals example from the MySQL docs and this sample below works nicely against that and logs the next incremented ID.
function foo() {
var conn = Jdbc.getCloudSqlConnection("jdbc:google:rdbms://<instance>/<db>");
var stmt = conn.createStatement();
var sql = "INSERT INTO animals (name) VALUES ('dog')";
var count = stmt.executeUpdate(sql,1)//pass in any int for auto inc IDs back
var rs = stmt.getGeneratedKeys();
//if you are only expecting one row back, no need for while loop
// just do rs.next();
while(rs.next()) {
Logger.log(rs.getString(1));
}
rs.close();
stmt.close();
conn.close();
}

Linq initialize object

I have the following linq:
var recprec = (from rc in db.tblTrucks
where rc.ID == recid
select rc
}).FirstOrDefault();
How do I intialize recprec and then fill it in late. For example with a string we can do something like String xyz and then use that string later.
I need to do the same with var recprec.
I tried doing
Object recprec = null;
recprec = (from rc in db.tblTrucks
where rc.ID == recid
select rc
}).FirstOrDefault();
I am doing this as I need to use recprec in a number of different places in my program. If I keep it as var recprec... it goes out of scope so like to declare it at top where it is in scope througout my program.
In your specific case, your LINQ query will return whatever tblTrucks contains. If it's a DataTable, your query will return a single DataRow. If it's a List<Truck>, it'll return a single Truck. You just have to know what's contained within the collection you're querying.

How to return a RefCursor from Oracle function?

I am trying to execute a user-defined Oracle function that returns a RefCursor using ODP.NET. Here is the function:
CREATE OR REPLACE FUNCTION PKG.FUNC_TEST (ID IN TABLE.ID%type)
RETURN SYS_REFCURSOR
AS
REF_TEST SYS_REFCURSOR;
BEGIN
OPEN REF_TEST FOR
SELECT *
FROM TABLE;
RETURN REF_TEST;
END;
/
I can call this function in Toad (select func_test(7) from dual) and get back a CURSOR. But I need to get the cursor using C# and ODP.NET to fill a DataSet, but I keep getting a NullReferenceException - "Object reference not set to an instance of an object". Here is what I have for that:
OracleConnection oracleCon = new OracleConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
OracleCommand sqlCom = new OracleCommand("select func_test(7) from dual", oracleCon);
sqlCom.Parameters.Add("REF_TEST", OracleDbType.RefCursor, ParameterDirection.ReturnValue);
OracleDataAdapter dataAdapter = new OracleDataAdapter();
dataAdapter.SelectCommand = sqlCom;
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet); //FAILS HERE with NullReferenceException
I was able to find lots of info and samples on using stored procedures and ODP.NET, but not so much for returning RefCursors from functions.
EDIT: I do not want to explicitly add input parameters to the OracleCommand object (i.e. sqlCom.Parameters.Add("id", OracleDbType.Int32,ParameterDirection.Input).Value = 7;) as that makes it difficult to implement this as a generic RESTful web service, but I'm reserving it as my last resort but would use stored procedures instead.
Any help is much appreciated!
I think you are missing the sqlCom.ExecuteNonQuery();
also, instead of running the select func_test(7) from dual; lets switch it to run the function and pass in the param
OracleConnection oracleCon = new OracleConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
// Set the command
string anonymous_block = "begin " +
" :refcursor1 := func_test(7) ;" +
"end;";
//fill in your function and variables via the above example
OracleCommand sqlCom= con.CreateCommand();
sqlCom.CommandText = anonymous_block;
// Bind
sqlCom.Parameters.Add("refcursor1", OracleDbType.RefCursor);
sqlCom.Parameters[0].Direction = ParameterDirection.ReturnValue;
try
{
// Execute command; Have the parameters populated
sqlCom.ExecuteNonQuery();
// Create the OracleDataAdapter
OracleDataAdapter da = new OracleDataAdapter(sqlCom);
// Populate a DataSet with refcursor1.
DataSet ds = new DataSet();
da.Fill(ds, "refcursor1", (OracleRefCursor)(sqlCom.Parameters["refcursor1"].Value));
// Print out the field count the REF Cursor
Console.WriteLine("Field count: " + ds.Tables["refcursor1"].Columns.Count);
}
catch (Exception e)
{
Console.WriteLine("Error: {0}", e.Message);
}
finally
{
// Dispose OracleCommand object
cmd.Dispose();
// Close and Dispose OracleConnection object
con.Close();
con.Dispose();}
this is based on the example ODP that can be found # %ora_home%\Client_1\ODP.NET\samples\RefCursor\Sample5.csproj
If you want to avoid (for better or worst!) the custom built param collection for each proc/function call you can get around that by utilizing anonymous blocks in your code, I have ammended (once again untested!) the code above to reflect this technique.
Here is a nice blog (from none other than Mark Williams) showing this technique.
http://oradim.blogspot.com/2007/04/odpnet-tip-anonymous-plsql-and.html

what are the OleDbTypes associated with Oracle Number and varchar2 when calling a function

I'm trying to map OleDb parameters to an Oracle Function. I was able to do this using the System.Data.Oracle namespace but then found that this is depricated, so I thought i would re-write it as OldDb to avoid installing the Oracle Provider.
I have defined the following oracle function as an example:
create function GetImagePath (AIRSNumber in number)
return varchar2
is
begin
return '\\aiimg524\images\Ofndrtrk\2010\01\0kvrv1p000lcs74j';
end;
and I'm calling it using the following code:
using (var command = new OleDbCommand())
{
command.Connection = con;
command.CommandText = ConfigurationManager.AppSettings[OTRAK_PHOTO_FUNC];
command.CommandType = CommandType.StoredProcedure;
string parm = ConfigurationManager.AppSettings[OTRAK_PHOTO_PARM];
command.Parameters.Add(parm, OleDbType.Decimal); // maps to oracle Number
command.Parameters[parm].Direction = ParameterDirection.Input;
command.Parameters[parm].Value = airsNumber;
command.Parameters.Add(RETURN_VALUE, OleDbType.Variant); // maps to Oracle varchar2
command.Parameters[RETURN_VALUE].Direction = ParameterDirection.ReturnValue;
try
{
con.Open();
command.ExecuteNonQuery();
path = command.Parameters[RETURN_VALUE].Value.ToString();
}
I tried a bunch of different OleDB types for the parameter and the return value. the current attempt is from a mapping table i found on the web that said number = decimal and varchar2 = variant. I'm about to try every permutation of types in the enum and wanted to ask for help. the not so useful error message i get is:
[System.Data.OleDb.OleDbException] = {"ORA-06550: line 1, column 7:\nPLS-00306: wrong number or types of arguments in call to 'GETIMAGEPATH'\nORA-06550: line 1, column 7:\nPL/SQL: Statement ignored"}
This actually had nothing to do with the type of the parameters but the order. Using the OleDb provider for Oracle does not respect the names of the parameters in the parameter collection but rather the order that the parameters are added. Wwhen calling an oracle function, the return value is a free parameter that must be declared first. by adding my return value parameter and then the actual function parameter things started working.
using the command.Parameters.AddWithValue(parm, value) also simplifies things a bit.

Resources