I need to run two statements like so:
Select amount from db where ID=5
DELETE from db where ID=5
Currently I prepare and run two different statements. I wonder if there is a way to combine it in one statement.
Basically all I need to do is to get an amount column from the row before it is deleted.
SQLite does not support this extension to standard SQL -- you do have to use both statements, SELECT first, DELETE next. You can wrap them in a transaction, of course, (BEGIN and COMMIT statements before and after will guarantee that), to guarantee atomicity and consistency.
If you just want to select rows and delete them in one pass, you can use the returning clause in the delete statement.
For instance:
delete from myTable returning *
The delete statement has all select functionalities possible such as with and where that permits to select rows with any logic.
Assuming that your calling thread/process has a unique identifier (e.g. thread_id), I think a viable approach would be to add a flag (say, "handlerid") to your table, which is set to null on insert, and then do:
update db set handlerid = <my_thread_id> where handlerid is null;
select * from db where handlerid is not null and handlerid = <my_thread_id>;
delete from db where handlerid is not null and handlerid = <my_thread_id>;
Not sure how it would perform vs a transaction but can't think of any reason it would be materially worse (might even be better), and using this approach the code seems about as straightforward as you can get. unlike a transaction, it won't require you to loop in the case that a transaction fails, in order to be sure that all outstanding elements that were in the table at the time of the most recent SELECT got processed.
It's late but for future visitor. In my case I did like below
I want to delete that ID where amount = 5 so I did this
public void selectAndDelete() {
try {
SQLiteDatabase db = this.getWritableDatabase();
int i=db.delete(table_name, "ID = (select ID from table_name where amount = 5)", null);
if(i>0)
{
// I'm inserting here new record
}
} catch (SQLException e) {
}
}
So, In your case you need to modify where condition like you want
You can do this by separating the two statements with a semicolon, e.g. (using the .NET port of SQLite):
using (SQLiteConnection conn = new SQLiteConnection("Data Source=fie.db3"))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "SELECT id FROM fies; DELETE FROM fies WHERE id = 5;";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader[0]);
}
}
}
}
Related
I need to check if a book rating for specific book from specific person exists.
If it does update it, if it doesnt create it.
I am getting a whole bunch of wrong errors for 9th 10th.... 12th parameter missing while I count only 8
My mariaDB version is 10.5.8-MariaDB.
My code:
const createBookRate = async (userId, bookId, rate) => {
const sql = `
SELECT IF(EXISTS( SELECT * from rates WHERE rates.users_id=? AND rates.books_id=? ),
UPDATE rates SET rates.rate=? WHERE rates.users_id=? AND rates.books_id=?,
INSERT INTO rates(users_id, books_id, rate))
VALUE (?,?,?,?,?,?,?,?);
`
const { insertId } = await pool.query(sql, [userId, bookId, rate, userId, bookId, userId, bookId, rate])
const rateEntry = await getBookRate(insertId)
return rateEntry
}
You cannot perform an UPDATE or an INSERT inside the IF clause of a SELECT statement, those must be performed separately.
To perform this in a safe manner, use a transaction and first lock the selected row with SELECT ... FOR UPDATE, then either UPDATE or INSERT it and finally COMMIT the transaction.
If the table has a primary key, you can use INSERT ... ON DUPLICATE KEY UPDATE to either insert the row or update it, depending on whether it exists or not. This allows everything to be done in one step without having to first select the affected rows.
In my case (I happen to have only two types for each entry, so 2 partitions, and the row key is unique) I can write an iterative set of queries going over all possible partitions like this:
TableOperation retrieveOperation = TableOperation.Retrieve<JobStatus>(Mode.GreyScale.Description(), id);
TableResult query = await table.ExecuteAsync(retrieveOperation);
if (query.Result != null)
{
return new OkObjectResult((JobStatus)query.Result);
}
else
{
retrieveOperation = TableOperation.Retrieve<JobStatus>(Mode.Sepia.Description(), id);
query = await table.ExecuteAsync(retrieveOperation);
if (query.Result != null)
{
return new OkObjectResult((JobStatus)query.Result);
}
}
return new NotFoundResult();
The thing is, that is clearly inefficient (imagine if there were hundreds of types!). Does azure storage tables provide an efficient means to query when you know only the row key?
Does azure storage tables provide an efficient means to query when you
know only the row key?
Simple answer to your question is no, there's no efficient way to query table when you only know the RowKey. Table Service will do full table scan going from one partition to another and find entities with matching RowKey.
In your case, you would probably want to use TableQuery to create your query and then either call ExecuteQuery or ExecuteQuerySegmented to get query results.
TableQuery query = new TableQuery().Where("RowKey eq 'Your Row Key'");
var result = table.ExecuteQuery(query);
I'm using Azure Mobile App with Xamarin.Forms to create an offline capable mobile app.
My solution is based on https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter3/client/
Here is the code that I use for offline sync :
public class AzureDataSource
{
private async Task InitializeAsync()
{
// Short circuit - local database is already initialized
if (client.SyncContext.IsInitialized)
{
return;
}
// Define the database schema
store.DefineTable<ArrayElement>();
store.DefineTable<InputAnswer>();
//Same thing with 16 others table
...
// Actually create the store and update the schema
await client.SyncContext.InitializeAsync(store, new MobileServiceSyncHandler());
}
public async Task SyncOfflineCacheAsync()
{
await InitializeAsync();
//Check if authenticated
if (client.CurrentUser != null)
{
// Push the Operations Queue to the mobile backend
await client.SyncContext.PushAsync();
// Pull each sync table
var arrayTable = await GetTableAsync<ArrayElement>();
await arrayTable.PullAsync();
var inputAnswerInstanceTable = await GetTableAsync<InputAnswer>();
await inputAnswerInstanceTable.PullAsync();
//Same thing with 16 others table
...
}
}
public async Task<IGenericTable<T>> GetTableAsync<T>() where T : TableData
{
await InitializeAsync();
return new AzureCloudTable<T>(client);
}
}
public class AzureCloudTable<T>
{
public AzureCloudTable(MobileServiceClient client)
{
this.client = client;
this.table = client.GetSyncTable<T>();
}
public async Task PullAsync()
{
//Query name used for incremental pull
string queryName = $"incsync_{typeof(T).Name}";
await table.PullAsync(queryName, table.CreateQuery());
}
}
The problem is that the syncing takes a lot of time even when there isn't anything to pull (8-9 seconds on Android devices and more than 25 seconds to pull the whole database).
I looked at Fiddler to find how much time takes the Mobile Apps BackEnd to respond and it is about 50 milliseconds per request so the problem doesn't seem to come from here.
Does anyone have the same trouble ? Is there something that I'm doing wrong or tips to improve my sync performance ?
Our particular issue was linked to our database migration. Every row in the database had the same updatedAt value. We ran an SQL script to modify these so that they were all unique.
This fix was actually for some other issue we had, where not all rows were being returned for some unknown reason, but we also saw a substantial speed improvement.
Also, another weird fix that improved loading times was the following.
After we had pulled all of the data the first time (which, understandably takes some time) - we did an UpdateAsync() on one of the rows that were returned, and we did not push it afterwards.
We've come to understand that the way offline sync works, is that it will pull anything that has a date newer than the most recent updated at. There was a small speed improvement associated with this.
Finally, the last thing we did to improve speed was to not fetch the data again, if it already had cached a copy in the view. This may not work for your use case though.
public List<Foo> fooList = new List<Foo>
public void DisplayAllFoo()
{
if(fooList.Count == 0)
fooList = await SyncClass.GetAllFoo();
foreach(var foo in fooList)
{
Console.WriteLine(foo.bar);
}
}
Edit 20th March 2019:
With these improvements in place, we are still seeing very slow sync operations, used in the same way as mentioned in the OP, also including the improvements listed in my answer here.
I encourage all to share their solutions or ideas on how this speed can be improved.
One of the reasons for the slow Pull() is when more than (10) rows get the same UpdatedAt value. This happens when you update the rows at once, for example running an SQL command.
One way to overcome this is to modify the default trigger on the tables. To ensure every row gets a unique UpdateAt, we did something like this:
ALTER TRIGGER [dbo].[TR_dbo_Items_InsertUpdateDelete] ON [dbo].[TableName]
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
DECLARE #InsertedAndDeleted TABLE
(
Id NVARCHAR(128)
);
DECLARE #Count INT,
#Id NVARCHAR(128);
INSERT INTO #InsertedAndDeleted
SELECT Id
FROM inserted;
INSERT INTO #InsertedAndDeleted
SELECT Id
FROM deleted
WHERE Id NOT IN
(
SELECT Id
FROM #InsertedAndDeleted
);
--select * from #InsertedAndDeleted;
SELECT #Count = Count(*)
FROM #InsertedAndDeleted;
-- ************************ UpdatedAt ************************
-- while loop
WHILE #Count > 0
BEGIN
-- selecting
SELECT TOP (1) #Id = Id
FROM #InsertedAndDeleted;
-- updating
UPDATE [dbo].[TableName]
SET UpdatedAt = Convert(DATETIMEOFFSET, DateAdd(MILLISECOND, #Count, SysUtcDateTime()))
WHERE Id = #Id;
-- deleting
DELETE FROM #InsertedAndDeleted
WHERE id = #Id;
-- counter
SET #Count = #Count - 1;
END;
END;
I am developing a mobile application with Ionic and SQLITE database. I want a scenario where same record should not be inserted twice for Inventory operation. I am checking the database as follows:
var query = "SELECT COUNT(*) FROM productScan WHERE uniqueId = (?) AND sync = \'N\'";
$cordovaSQLite.execute(db, query, [uniqueId]).then(function (res) {
alert(JSON.stringify(res));
}, function (err) {
alert(JSON.stringify(err));
});
what happen here is when i install the app for the first time and run it then after scan operation when this code run for duplication check, it gives me following output even though there is no record in database
{"rows":{"length":1},""rowsAffected":0}
I am new to Structured Query Language(SQL). I am not able to parse the result here. The result is coming wrong. Is the query needs to be reformatted or any different way to achieve the goal?
Thanks for your time.
BEST way to do this is by giving ALIAS to the COUNT(*) .
something like this
db.executeSql("select count(*) AS TOTAL from mydebit where aid = ?", [
parseInt(this.mydata)
]);
and then
console.log(data.rows.item(0).TOTAL)
so we can easily give the name to the return result and use the to get he row value
cheersss.....!!!!!!!!!
I do it in this way
JSON.stringify(data.rows.item(0)['COUNT(*)'])
Somehow i managed to achieve it in a different way
var query = "SELECT * FROM productScan WHERE uniqueId = (?) AND sync = \'N\'";
$cordovaSQLite.execute(db, query, [uniqueId]).then(function (res) {
if (res.rows.length == 0) {
//processed the operation
}else{
alert('You have already scanned this asset!.');
}
var query = "SELECT COUNT(*) FROM productScan WHERE uniqueId = (?) AND sync = \'N\'";
$cordovaSQLite.execute(db, query, [uniqueId]).then(function (res) {
just parse the result,(json.parse(res)) and find by rowsAffected like
if(rowsAffected != 0)
{
//just do the operation
}
else {
//terminate
}
I have created windows service for data-insertion.Time interval is one min.After one min, data insert into table.Data get inserted into table at multiple time.I don't want to that,only one time.How to do that?May I need to check in database wether entry is there or nor if not add.
You can use this query before inserting the data.
IF EXISTS(SELECT * FROM dbo.YourTable WHERE Name = #Name)
RETURN
-- here, after the check, do the INSERT
You might also want to create a UNIQUE INDEX on your Name column to make sure no two rows with the same value exist:
CREATE UNIQUE NONCLUSTERED INDEX UIX_Name
ON dbo.YourTable(Name)
Hope this help you.
//You can do like this in ur code
if (ChkRecordExist() == true)
{
//Do nothing
}
else
{
// insert operation
}
protected bool ChkRecordExist()
{
//here logic for record exist or not.
//if record is exist return true else return false
}