Flex: sqlite last_insert_rowid over multiple insert calls - apache-flex

I have file with multiple SQL statements in it to be executed.
INSERT INTO reports (a,b,c) VALUES (1,2,3);
INSERT INTO units (report_id, e, f, g) VALUES ( (SELECT last_insert_rowid() FROM reports), 4, 5, 6);
INSERT INTO elements (report_id, h, i, j) VALUES ( (SELECT last_insert_rowid() FROM reports), 7, 8, 9);
The FROM reports section of the sub-selection does nothing.
What ends up happening is:
A row is inserted into reports and the reports.id field is autoincremented
A row is inserted into units with report_id being equal to the reports id
A row is inserted into elements with report_id being equal to units.id of the last row inserted
This is works as described in the sqlite documentation.
My issue is that I want all the queries subsequent to the report insert to use report.id.
Is there anyway I can get this to work on the database end without having to resort to a solution in as3?

There is a way to do this, but it is in AS3 using parameters.
What is done is instead of using the SELECT last_insert_row() function in each call, replace it with a parameter.
INSERT INTO elements (report_id, h, i, j) VALUES (#id, 7, 8, 9);
Now in my code I have to split the file into an array so that each individual queries is process separately (this is how AS3 implements sqlite's API).
var sqlArray:Array = sql.split(";\n\n");
Now what I do is execute the first statement for importing the report itself.
statement.text = sqlArray[0];
statement.execute();
Now the fun part. You need to get the id back out. So we run another query.
statement.text = "SELECT last_insert_rowid() as ID";
statement.execute();
var id:int = statement.getResult().data[0].id;
Now we can loop through the rest of the queries using the id as a parameter.
for(var i:int = 1; i < sqlArray.length - 1; i++) {
/**
* start at 1 because we already inserted the report
* end at length -1 because our last entry is empty because of how split works on our data
**/
statement.text = sqlArray[i];
statement.parameters['#ID'] = id;
statement.execute();
}
This is a little more complicated, but not much and it ends up working.
Everything rolled together into a single function (omitting a lot of class overhead) would be:
function importFromSQLString(sql:String):void {
try{
connection.begin();
var sqlArray:Array = sql.split(";\n\n");
statement.text = sqlArray[0];
statement.execute();
statement.text = "SELECT last_insert_rowid() as ID";
statement.execute();
var id:int = statement.getResult().data[0].id;
for(var i:int = 1; i < sqlArray.length - 1; i++) {
statement.text = sqlArray[i];
statement.parameters['#ID'] = id;
statement.execute();
}
connection.commit();
statement.clearParameters();
} catch (e:Error) {
connection.rollback(); //cleanup if there was a failure
}
}

Related

How do i get the Count of InventSerialId from InventDim

How do i create a query or using select to get the count of InventSerialId base on a given Itemid, InventLocationId and where the inventSum.PhysicalInvent > 0 or inventSum.Picked > 0.
This is not directly possible using X++.
Consider:
static void _TestDim(Args _args)
{
ItemId itemId = '123';
InventSum inventSum;
InventDim inventDim;
Query q = new Query();
QueryBuildDataSource ds = q.addDataSource(tableNum(InventSum), 's');
QueryRun qr;
;
// ds.addRange(fieldNum(InventSum,ItemId)).value(queryValue(itemId));
ds.addRange(fieldNum(InventSum,Closed)).value(queryValue(NoYes::No));
ds.addGroupByField(fieldNum(InventSum,ItemId));
ds.addSelectionField(fieldNum(InventSum,PhysicalInvent),SelectionField::Sum);
ds.addSelectionField(fieldNum(InventSum,Picked),SelectionField::Sum);
q.addHavingFilter(ds, fieldStr(InventSum,PhysicalInvent), AggregateFunction::Sum).value('>0');
// q.addHavingFilter(ds, fieldStr(InventSum,Picked), AggregateFunction::Sum).value('((s.Picked >0)||(s.PhysicalInvent>0))'); // This is not allowed
ds = ds.addDataSource(tableNum(InventDim), 'd');
ds.joinMode(JoinMode::InnerJoin);
ds.relations(true);
ds.addGroupByField(fieldNum(InventDim,InventSerialId));
ds.addRange(fieldNum(InventDim,InventSerialId)).value('>""');
info(q.dataSourceNo(1).toString());
qr = new QueryRun(q);
while (qr.next())
{
inventSum = qr.getNo(1);
inventDim = qr.getNo(2);
info(strFmt('%1 %2: %3 %4', inventSum.ItemId, inventDim.InventSerialId, inventSum.PhysicalInvent, inventSum.Picked));
break;
}
}
Here you aggreate PhysicalInvent and picked, and you can apply a having-filter using the query method addHavingFilter.
However, you cannot have that combined with another having-filter using a SQL or-statement.
If you try with a query expression, you will get a run-time error.
What you can do is create two views with each filter, then combine them using a union view. This is tricky but doable.
The first should select positive PhysicalInvent and the second should select PhysicalInvent == 0 and positive Picked.

Can SQLite return the id when inserting data?

I'm using sqlite3.exe to execute queries against my DB, using the following code.
public static string QueryDB(string query)
{
string output = System.String.Empty;
string error = System.String.Empty;
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = "C:\\sqlite\\sqlite3.exe";
startInfo.Arguments = "test.db " + query;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
try
{
using(System.Diagnostics.Process sqlite3 = System.Diagnostics.Process.Start(startInfo))
{
output = sqlite3.StandardOutput.ReadToEnd();
error = sqlite3.StandardError.ReadToEnd();
sqlite3.WaitForExit();
}
}
catch (System.Exception ex)
{
System.Console.WriteLine(ex.ToString());
return null;
}
return output;
}
I'm inserting data into a table, and I'd like it to return the id of the inserted data. Is there a way to get SQLite to do this?
For example, my query might look like this "INSERT INTO mytable (some_values) VALUES ('some value');". After this query is run, I'd like output to contain the rowid of the inserted data. Is there any way to do this (a command line switch, etc.)?
A possible workaround, is to run two commands against the DB. First insert the data, then get the last inserted row id. In which case, the query would look like this "\"INSERT INTO mytable (some_values) VALUES ('some value'); SELECT last_insert_rowid();\""
You should not use max(id) or similar function in DB.
In this specific case it can work, under the condition that you use ONE connection and ONE thread to write data to DB.
In case of multiple connections you can get wrong answer.
From version SQLite 3.35.0 it supports returning close in the insert statement (SQLite Returning Close)
create table test (
id integer not null primary key autoincrement,
val text
);
insert into table test(val) values (val) returning id;
Would you consider this:
select max(id) from your_table_name;
or embedded function last_insert_rowid()?

How to get the tables from AOT query in ax 2012

I have drop down in one page, I am selecting AOT query in first page then i will click on next button, then it has to show tables related to that query
If you have a query name, you can loop through all of its datasources like this:
str queryName = "ActivityListOpen";
int i, dbcount;
QueryBuildDataSource qbds;
Query query = new Query(queryName);
dbcount = query.dataSourceCount();
for (i = 1; i <= dbcount; i++)
{
qbds = query.dataSourceNo(i);
info(qbds.name());
}
You can also use table() method on QueryBuildDataSource to retrieve table Id.

Convert Linq to SQL

I have researched on the net and most result are converting from sql to linq and seldom have linq to sql.
this is the code which I want to convert to SQL :
using (CommerceEntities db = new CommerceEntities())
{
try
{
var query = (from ProductOrders in db.OrderDetails
join SelectedProducts in db.Products on ProductOrders.ProductID
equals SelectedProducts.ProductID
group ProductOrders by new
{
ProductId = SelectedProducts.ProductID,
ModelName = SelectedProducts.ModelName
} into grp
select new
{
ModelName = grp.Key.ModelName,
ProductId = grp.Key.ProductId,
Quantity = grp.Sum(o => o.Quantity)
} into orderdgrp where orderdgrp.Quantity > 0
orderby orderdgrp.Quantity descending select orderdgrp).Take(5);
RepeaterItemsList.DataSource = query;
RepeaterItemsList.DataBind();
}
catch (Exception exp)
{
throw new Exception("ERROR: Unable to Load Popular Items - " +
exp.Message.ToString(), exp);
}
}
You can attempt to run the LINQ statement in LinqPad. For examples on how to use LinqPad, check the answer here.
It has a tab to show the generated SQL statement.
Here's an article on logging in LINQ to SQL. It lets you specify a TextWriter to which to send the query.
Basically, you can write something like this:
db.Log = new System.IO.StreamWriter("linq-to-sql.log") { AutoFlush = true };
... where db is your data context.
In SQL you'd write something like this (although the produced code will look a lot different, since it is auto-generated):
SELECT TOP 5 Products.ModelName, Products.ProductID, SUM(OrderDetails.Quantity) qty
FROM OrderDetails
INNER JOIN Products ON OrderDetails.ProductID = Products.ProductID
GROUP BY Products.ProductID, Products.ModelName
HAVING qty > 0
ORDER BY qty DESC

Conditionally parameterize SQLite query in AIR

How can I conditionally parametrize a SQLite database in AIR?
For example this query:
//selectedID is the ID I want to select
query.text = "select * from table where id=#ID";
query.parameters['#ID']=selectedID;
But I want the where statement to appear only if selectedID is greater than 0.
What I would normally do is:
query.text = "select * from table"+(selectedID>0?" where id="+selectedID:'');
However, I read on the LiveDocs performance-wise it is better to use parameters.
Is it possible to parametrize a whole statement or that's only possible for values?
Or maybe this is good-enough:
query.text = "select * from table"+(selectedID>0?" where id=#ID":'');
query.parameters['#ID']=selectedID;
if (selectedID > 0)
{
query.text = .....
query.parameters['#ID'] = ...
}
else
{
query.text = .....
{

Resources