Submitting multiple query transactions in CFscript - mysql

I am having trouble finding the correct syntax to execute multiple MySQL statements at once, like with cftransaction. I'm trying to implement this in a CFC in pure cfscript.
<cftransaction>
DROP TABLE IF EXISTS SOME_TEMP_TBL;
CREATE TABLE SOME_TEMP_TBL AS
(
SELECT * FROM ANOTHER_TBL
);
DROP TABLE IF EXISTS SOME_TEMP_TBL_2;
CREATE TABLE SOME_TEMP_TBL_2 AS
(
SELECT * FROM ANOTHER_TBL_2
);
</cftransaction>
So I have the SQL statements chained together as a string:
var SQL = "
DROP TABLE IF EXISTS SOME_TEMP_TBL;
CREATE TABLE SOME_TEMP_TBL AS
(
SELECT * FROM ANOTHER_TBL
);
DROP TABLE IF EXISTS SOME_TEMP_TBL_2;
CREATE TABLE SOME_TEMP_TBL_2 AS
(
SELECT * FROM ANOTHER_TBL_2
);
";
And if I understand right I think I need to use a transaction {} block. But do I put raw MySQL code in there? Currently I'm trying to attach it to a Query object but Base.cfc (Railo) is throwing an error saying the datasource isn't defined.
transaction
{
qTrans = new Query();
qTrans.setSQL(SQL);
qTrans.execute();
qTrans.setDatasource(variables.instance.datasource.getDSN());
if (good)
{
transaction action="commit";
} else {
transaction action="rollback";
}
}
Have also tried just SQL.execute() but of course execute() isn't defined for a string & it wouldn't relate to any DB anyway...
Also, is the if(good) portion required? By default does if(good) test for whether or not a MySQL error occurred? And is transaction action="commit" what actually sends the SQL script?
Do I need to split these up into separate Query objects and run them sequentially? And if so what's the point of even having the transaction block in CFscript?
I know I'm way off here but I'm having a hard time navigating the CF documentation around this. If anyone knows of a good source specifically for CFscript references I could really use one, because I struggle with Adobe's version.

Try this code
try {
transaction {
qTrans = new Query();
qTrans.setDatasource(variables.instance.datasource.getDSN());
qTrans.setSQL(SQL);
qryRes = qTrans.execute();
TransactionCommit();
}
} catch(database e) {
TransactionRollback();
}

Related

How to pass an array of parameters to MySql select ... in

I wish to select an array of records with id 2, 4, 6 from a mysql database file. I am trying to pass an array of integers to a Mysql store procedure. But I fail to create a working stored procedure.
Would you help me compose one?
This is the C# code
public static List<PhotoComment> GetPhotos(int[] _ids)
{
MySqlConnection _con = Generals.GetConnnection();
List<PhotoComment> _comments = new List<PhotoComment>();
try
{
MySqlCommand _cmd = new MySqlCommand("Photos_GetPhotosByIDs", _con);
_cmd.CommandType = CommandType.StoredProcedure;
_cmd.Parameters.AddWithValue("#_ids", _ids);
_con.Open();
MySqlDataReader _reader = _cmd.ExecuteReader();
while (_reader.Read())
{
PhotoComment _comment = new PhotoComment(_reader.GetInt32("cID"), _reader.GetInt32("cFID"), _reader.GetString("cUser"), _reader.GetString("cContent"), _reader.GetDateTime("cDate"), _reader.GetBoolean("cChecked"));
_comments.Add(_comment);
}
_con.Close();
}
catch (Exception _ex)
{
_con.Close();
ReportMgr.ReportException(_ex.Message);
}
return _comments;
}
this is the mysql
CREATE DEFINER=root#localhost PROCEDURE Photos_GetPhotosByIDs(in _ids int[])
BEGIN
select * from tbl_photos where ID in _ids;
END
There are no array types in MySQL. You can use table (temporary table) instead. Fill the bale with id values and join tables to get desired result.
I'm not sure if I'm getting your question right but what I think you're asking is how to send multiple values into an input parameter of a stored procedure.
If that's what you're asking, the following link may help. Not sure if such a feature exists in MySql but in SQL Server, it's called "Table-Valued Parameters" - TVP in short.
TVP allows you to pass multiple values into a single input parameter. Hope this helps: https://msdn.microsoft.com/en-us/library/bb675163(v=vs.110).aspx

Stored Procedure for multiple value with single parameter in SQL Server

I have this form in C# with a listbox where I selected 4 items. Now I want to make single stored procedure using which I can find data from single table for all this selected item with single parameter.
As I am a beginner when it comes to SQL Server, I completely don't know this type of procedure
Thanks, but this is not my question's answer
I want a Single Stored Procedure for all Items which are selected in ListBox
Create Procedure procedureName
(
#ItemName varchar(50),
)
AS
BEGIN
(
Select * from item_master where item_name = #ItemName
)
END
by this Query i can find data for one ItemName, but i want for all selected Items in Listbox, even I don't know the C# code also,
so plz help me....
This is a very simple example that does what you want. You would not want to use hard-coded connection strings, especially in-line, and you would want error-handling, but I am going for as much clarity as possible. You would also probably want to make the column length greater than 50 characters, but I made it match your column definition.
Also, I would recommend a generic approach, passing keys (column names) and values, so as to be able to use it for any sort of criteria, but you asked that I keep it to exactly what you require, so I trimmed it down to the essential.
This example returns all the Employees with FirstName matching any in the list passed to the stored procedure (as a user-defined table type).
First, create a user-defined table type (to hold the values you want to pass to the stored procedure) in your SQL Server database as follows:
CREATE TYPE [dbo].[FilterValues] AS TABLE(
[Value] [varchar](50) NOT NULL,
PRIMARY KEY CLUSTERED
(
[Value] ASC
)
)
The stored procedure to return the Employees looks as follows (note that it has the user-defined table type as the type of the single parameter passed in):
CREATE PROCEDURE [dbo].[GetEmployees] (
#FirstNameFilterValues dbo.FilterValues READONLY
)
AS
BEGIN
SELECT * FROM Employees
INNER JOIN #FirstNameFilterValues fv ON fv.Value = Employees.FirstName;
END
That's the SQL Server side done. To call it from C#, you can create a DataTable with a single column matching the column name and populate it with the values you want. In this simple example, I populate it with two names, but it could be as many as you want.
var filterValuesDataTable = new DataTable();
filterValuesDataTable.Columns.Add(new DataColumn("Value", typeof(string)) { AllowDBNull = false });
filterValuesDataTable.Rows.Add("Frodo");
filterValuesDataTable.Rows.Add("Sam");
using (var connection = new SqlConnection("server=.;Initial Catalog=Test;Integrated Security=True;"))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = "GetEmployees";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#FirstNameFilterValues", filterValuesDataTable);
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine("{0} {1}", reader["FirstName"], reader["LastName"]);
}
reader.Close();
}
}
connection.Close();
}

Sqljocky, transactioned query with multiple sets of parameters

I'm using sqljocky to insert data into a MySQL database. I need to truncate a table first, then insert multiple rows in it. I would do this in a single transaction, but it seems that sqljocky doesn't support this at all now (or maybe I'm quite new in dart and sqljocky).
The solution I found is the following, but I was wondering if there's a better one.
// Start transaction
pool.query('START TRANSACTION').then((r) {
// Truncate table
pool.query('TRUNCATE myTable').then((r) {
// Prepare statement to insert new data
pool.prepare('REPLACE INTO myTable (Id, Name, Description) VALUES (?,?,?)').then((query) {
// Execute query inserting multiple rows
query.executeMulti(myArrayValues).then((results) {
// Other stuff here
pool.query('COMMIT').then((r) {
...
To be honest, I'm still wondering if this code really executes a transactioned query!
Here's the same code rewritten with transaction support:
// Start transaction
pool.startTransaction().then((trans) {
// Delete all from table
trans.query('DELETE FROM myTable WHERE 1=1').then((r) {
// Prepare statement
trans.prepare('REPLACE INTO myTable (Id, Name, Description) VALUES (?,?,?)').then((query) {
// Execute query inserting multiple rows
query.executeMulti(myArrayValues).then((results) {
// Stuff here
// Commit
trans.commit().then((r) { ...
Use ConectionPool.startTransaction().
* You
* must use this method rather than `query('start transaction')` otherwise
* subsequent queries may get executed on other connections which are not
* in the transaction.
Haven't tried it myself yet.

error handling when performing 2 mysql queries

I have constructed a function where two queries are performed. Both of these queries insert data into two separate tables, data that is related to the registration of a user.
In one table things like username,password are held and in the other table stuff like address, phone etc...
Here is the function:
function register_biz_user($post,$connection)
{
$name=$connection-> real_escape_string($_POST['name']);
$lastname= $connection->real_escape_string($_POST['lastname']);
$pass_hashed = password::hash($_POST['password']);
$passwd= $connection->real_escape_string($pass_hashed);
$buztype= $connection->real_escape_string($_POST['buztype']);
$usertype= $connection->real_escape_string($_POST['usertype']);
$address= $connection->real_escape_string($_POST['address']);
$city= $connection->real_escape_string($_POST['city']);
$municipality= $connection->real_escape_string($_POST['municipality']);
$url= $connection->real_escape_string($_POST['wwwaddress']);
$email= $connection->real_escape_string($_POST['e-mail']);
$phone= $connection->real_escape_string($_POST['phone']);
$hash =$connection->real_escape_string(md5( rand(0,1000) )) ;
$connection->set_charset("utf8");
$result1 = $connection->query("insert into users values
(NULL,'" .$name. "','" .$lastname . "','".$email."','". $passwd."','".
$hash."','". $usertype."')");
if (!$result1) {
throw new Exception('error');
return false;
}
else{$result2=$connection->query("insert into business_users values
('".$connection->insert_id."','" .$address."','".$url ."','".$phone.
"','".$city. "','".$municipality. "','".$buztype. "')");
}
if(!$result2)
{ throw new Exception('error');
return false;}
return true;
}
And here is my problem:
If you look at the code you might notice that there is the problem that the 1st query runs without problem and the second throws an exception or vice verca.
My point is that there is the danger that the db WILL have ONLY partial data of the registered user. The goal is that either both queries run successfully or none runs.
How I must write the above code such that I can achieve the above statement?
I hope I was clear enough.
Use transactions: http://dev.mysql.com/doc/refman/5.0/en/commit.html
BEGIN
... queries ...
COMMIT or ROLLBACK
Note: "or vice verca" - that's not possible. In that case the 2nd query never gets executed.
Note2:
what's $post? seems to be unused.
why don't you use prepared statements? escaping everyhing is very error prone.
why do you have a procedural interface, passing $connection? you should have objects which know about the database connections... you have mixed code for at least 3 different layers... not necessary bad if you plan to create write-once-get-rid-of-code but probably not a good idea for a project which you have to maintain for months/years.

Do MERGE using Linq to SQL

SQL Server 2008 Ent
ASP.NET MVC 2.0
Linq-to-SQL
I am building a gaming site, that tracks when a particular player (toon) had downed a particular monster (boss). Table looks something like:
int ToonId
int BossId
datetime LastKillTime
I use a 3d party service that gives me back latest information (toon,boss,time).
Now I want to update my database with that new information.
Brute force approach is to do line-by-line upsert. But It looks ugly (code-wise), and probably slow too.
I think better solution would be to insert new data (using temp table?) and then run MERGE statement.
Is it good idea? I know temp tables are "better-to-avoid". Should I create a permanent "temp" table just for this operation?
Or should I just read entire current set (100 rows at most), do merge and put it back from within application?
Any pointers/suggestions are always appreciated.
An ORM is the wrong tool for performing batch operations, and Linq-to-SQL is no exception. In this case I think you have picked the right solution: Store all entries in a temporary table quickly, then do the UPSERT using merge.
The fastest way to store the data to the temporary table is to use SqlBulkCopy to store all data to a table of your choice.
If you're using Linq-to-SQL, upserts aren't that ugly..
foreach (var line in linesFromService) {
var kill = db.Kills.FirstOrDefault(t=>t.ToonId==line.ToonId && t.BossId==line.BossId);
if (kill == null) {
kill = new Kills() { ToonId = line.ToonId, BossId = line.BossId };
db.Kills.InsertOnSubmit(kill);
}
kill.LastKillTime = line.LastKillTime;
}
db.SubmitChanges();
Not a work of art, but nicer than in SQL. Also, with only 100 rows, I wouldn't be too concerned about performance.
Looks like a straight-forward insert.
private ToonModel _db = new ToonModel();
Toon t = new Toon();
t.ToonId = 1;
t.BossId = 2;
t.LastKillTime = DateTime.Now();
_db.Toons.InsertOnSubmit(t);
_db.SubmitChanges();
To update without querying the records first, you can do the following. It will still hit the db once to check if record exists but will not pull the record:
var blob = new Blob { Id = "some id", Value = "some value" }; // Id is primary key (PK)
if (dbContext.Blobs.Contains(blob)) // if blob exists by PK then update
{
// This will update all columns that are not set in 'original' object. For
// this to work, Blob has to have UpdateCheck=Never for all properties except
// for primary keys. This will update the record without querying it first.
dbContext.Blobs.Attach(blob, original: new Blob { Id = blob.Id });
}
else // insert
{
dbContext.Blobs.InsertOnSubmit(blob);
}
dbContext.Blobs.SubmitChanges();
See here for an extension method for this.