Is it possible to perform a SELECT and an UPDATE in a single SQLite query? - sqlite

I might not be wording the title properly but I'm wondering if it's possible to both read data and update data in a single query (or multiple queries in a single call?) using SQLite.
As an example situation I would like to SELECT the current state of the database then UPDATE the state to something new all in one single atomic query.
Here is how I'm pulling this off using Postgres:
UPDATE migrations_lock
SET is_locked = 0
WHERE index = 1 RETURNING (
SELECT is_locked AS was_locked
FROM migrations_lock
WHERE index = 1
);
Likewise, I'm able to achieve the same thing in MySQL using a transaction:
START TRANSACTION;
SELECT is_locked AS was_locked
FROM migrations_lock
WHERE `index` = 1;
UPDATE migrations_lock
SET is_locked = 0
WHERE `index` = 1;
COMMIT;
Sadly, running the same Postgres query in SQLite returns the new data instead of the existing data. Running the equivalent MySQL query in SQLite form (BEGIN TRANSACTION) returns an error about nested transactions. Running the SELECT followed by the UPDATE query in a single call (without the transaction) results in the SELECT query running and the UPDATE query being ignored.
There is some additional context about how the query is being run in this pull request.

SQLite since version 3.33.0 supports UPDATE FROM see
https://www.sqlite.org/lang_update.html#update_from
Another possibility is to use a CTE (Common Table Expression) to drive an UPDATE as per
All common table expressions (ordinary and recursive) are created by prepending a WITH clause in front of a SELECT, INSERT, DELETE, or UPDATE statement. A single WITH clause can specify one or more common table expressions, some of which are ordinary and some of which are recursive.
https://www.sqlite.org/lang_with.html
An example of using a CTE to drive an update:-
DROP TABLE IF EXISTS test;
CREATE TABLE IF NOT EXISTS test (datee TEXT, other_colmumns);
INSERT INTO test VALUES ('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
,('not the date I wanted','otherdate')
;
SELECT rowid,* FROM test; /* result 1 prior to update */
/* The CTE driven UPDATE */
WITH x AS (SELECT rowid FROM test LIMIT 10,5)
UPDATE test SET datee = '19/12/2021' WHERE test.rowid IN (SELECT * FROM x)
;
SELECT rowid,* FROM test; /* result 2 after update */
DROP TABLE IF EXISTS test; /* clean up */
Result 1 being
Result 2 being
Modifying the CTE for multiple selects (2 ctes x and y):-
/* The CTE driven UPDATE */
WITH x AS (SELECT rowid FROM test LIMIT 10,5),
y as (SELECT rowid FROM test LIMIT 1,2)
UPDATE test SET datee = '19/12/2021' WHERE test.rowid IN (SELECT * FROM x UNION ALL SELECT * FROM y)
;
result 2 is then

Related

MariaDB - delete all values that are `not the max` of one column with a group by on another column

I have a table that is a list of updates over time timeOfOfferChange. I can grab the most recent value with the query below but is there a way to delete all the records that are not the max?
select asin, uniqueid, max(timeOfOfferChange) from tbl_sqs group by asin
You could use exists logic:
DELETE
FROM tbl_sqs t1
WHERE uniqueid NOT IN (SELECT uniqueid
FROM (
SELECT t2.uniqueid
FROM tbl_sqs t2
WHERE t2.asin = t1.asin AND
t2.timeOfOfferChange > t1.timeOfOfferChange
) t);

Retrive date wise data from SQLITE database kotlin

I have one SQlite database where i store some data with date.
Now i want to get data date wise like:
Month wise - it means i pass the value like Current date is EndDate to this month 1st date.
Year wise - it means i want to get data 1st-april-20..previews to 31-march-20..current
Start and End date wise - hear is which i pass date.
For that i got one solution is HERE for java.
But i have no idea this HOW TO WORK. Anyone please explain me how to work this and How to i get data as i mention above. FOR KOTLIN
TABLE
db.createTable(customerDetail, true,
credit_id to INTEGER + PRIMARY_KEY + AUTOINCREMENT,
credit_type to TEXT,
c_id to TEXT,
credit_amount to TEXT,
credit_date to TEXT,
addFrom to TEXT
)
UPDATE
For Month wise data i'll try below query like:
"SELECT * FROM $customerDetail WHERE $credit_date BETWEEN strftime('%d-%m-%Y', '$startDate') AND strftime('%d-%m-%Y', '$currentDate')"
/*SELECT * FROM CustomerDetail WHERE credit_date BETWEEN strftime('%d-%m-%Y', '01/02/2019') AND strftime('%d-%m-%Y', '23/02/2019')*/
But it's give me arralistSize = 0.
After that i can write new query like:
"SELECT * FROM $customerDetail WHERE $credit_date BETWEEN '$startDate' AND '$currentDate'"
/*SELECT * FROM CustomerDetail WHERE credit_date BETWEEN '01/02/2019' AND '23/02/2019'*/
In this query data will return. But it's return all data without any filtering.
If anyone knows why this work like this please help me.
MY DATA LIST
Thanks in advance.
Solution :
Solution for MONTH wise
I just change date format "dd/mm/yyyy" TO "yyyy/mm/dd" and re insert all data.
AND Fire below QUERY :
"SELECT * FROM $customerDetail WHERE $credit_date BETWEEN '$startDate' AND '$currentDate'"
SQLite does not have a Date data type like other RDBMS's. It treats dates as TEXT.
So when it compares the credit_date column it actually does compare strings.
This would be fine if you stored your dates in the format YYYY-MM-DD and compared against the same format.
But if you store your dates in the format DD/MM/YYYY then you can't compare.
So the best solution would be to change the format of the column credit_date to YYYY-MM-DD.
If this is not possible then you have to transform the string value of the column like this:
substr(credit_date, 7, 4) || '-' || substr(credit_date, 4, 2) || '-' || substr(credit_date, 1, 2)
Now you can use this in a query like:
SELECT * FROM $customerDetail
WHERE substr($credit_date, 7, 4) || '-' || substr($credit_date, 4, 2) || '-' || substr($credit_date, 1, 2)
BETWEEN '$startDate' AND '$currentDate'
But you have to make sure that $startDate and $currentDate are also in the format YYYY-MM-DD

sql - sqlite select with condition on date

I have an sqlite table with due_date. I would like to execute a query to select those records where due_date >= 2017/01/20:
SELECT * FROM todo WHERE 1 = 1 AND date(due_date) >=
date('2017-01-20') AND task_name LIKE '%%';

SQLITE equivalent for Oracle's ROWNUM?

I'm adding an 'index' column to a table in SQLite3 to allow the users to easily reorder the data, by renaming the old database and creating a new one in its place with the extra columns.
The problem I have is that I need to give each row a unique number in the 'index' column when I INSERT...SELECT the old values.
A search I did turned up a useful term in Oracle called ROWNUM, but SQLite3 doesn't have that. Is there something equivalent in SQLite?
You can use one of the special row names ROWID, OID or _ROWID_ to get the rowid of a column. See http://www.sqlite.org/lang_createtable.html#rowid for further details (and that the rows can be hidden by normal columns called ROWID and so on).
Many people here seems to mix up ROWNUM with ROWID. They are not the same concept and Oracle has both.
ROWID is a unique ID of a database ROW. It's almost invariant (changed during import/export but it is the same across different SQL queries).
ROWNUM is a calculated field corresponding to the row number in the query result. It's always 1 for the first row, 2 for the second, and so on. It is absolutely not linked to any table row and the same table row could have very different rownums depending of how it is queried.
Sqlite has a ROWID but no ROWNUM. The only equivalent I found is ROW_NUMBER() function (see http://www.sqlitetutorial.net/sqlite-window-functions/sqlite-row_number/).
You can achieve what you want with a query like this:
insert into new
select *, row_number() over ()
from old;
No SQLite doesn't have a direct equivalent to Oracle's ROWNUM.
If I understand your requirement correctly, you should be able to add a numbered column based on ordering of the old table this way:
create table old (col1, col2);
insert into old values
('d', 3),
('s', 3),
('d', 1),
('w', 45),
('b', 5465),
('w', 3),
('b', 23);
create table new (colPK INTEGER PRIMARY KEY AUTOINCREMENT, col1, col2);
insert into new select NULL, col1, col2 from old order by col1, col2;
The new table contains:
.headers on
.mode column
select * from new;
colPK col1 col2
---------- ---------- ----------
1 b 23
2 b 5465
3 d 1
4 d 3
5 s 3
6 w 3
7 w 45
The AUTOINCREMENT does what its name suggests: each additional row has the previous' value incremented by 1.
I believe you want to use the constrain LIMIT in SQLite.
SELECT * FROM TABLE can return thousands of records.
However, you can constrain this by adding the LIMIT keyword.
SELECT * FROM TABLE LIMIT 5;
Will return the first 5 records from the table returned in you query - if available
use this code For create Row_num 0....count_row
SELECT (SELECT COUNT(*)
FROM main AS t2
WHERE t2.col1 < t1.col1) + (SELECT COUNT(*)
FROM main AS t3
WHERE t3.col1 = t1.col1 AND t3.col1 < t1.col1) AS rowNum, * FROM Table_name t1 WHERE rowNum=0 ORDER BY t1.col1 ASC

Comparing two date of varchar and getdate

I have a database table field named User_Created_Date of type Varchar.I want to write a query to fetch all records where the difference between Today's date and User_Created_Date is greater than 31 days
pls help
Since your VARCHAR column's date format is DD/MM/YY, use:
select * from Your_Table
where DATEDIFF(day, CONVERT(datetime, User_Created_Date, 3), GETDATE()) > 31;

Resources