I have an Android Sqlite database and I'm trying to select the top 1000 rows by RANK number, because RANK is always changing I sometimes get duplicate rows with the same RANK number, what I would like to do is only keep the duplicate row containing the newest RANK based on its CREATED_DATE, I will visually display this below:
id rank created_date
1 1 1/1/2014
2 2 1/1/2021
3 3 1/1/2021
4 1 1/1/2021
The output I want is:
id rank created_date
2 2 1/1/2021
3 3 1/1/2021
4 1 1/1/2021
My current code gets close but doesn't remove duplicate RANK based on CREATED_DATE instead it removes them based on ID which I don't want and I haven't been able to find a way to do it by CREATED_DATE
Cursor c = theDatabase.query(DATABASE_TABLE, columns, RANK + " BETWEEN 1 AND 1000", null,
RANK, null, ID + " ASC");
This code above is removing duplicates based on ID which I don't want and gives this output below:
id rank created_date
1 1 1/1/2014
2 2 1/1/2021
3 3 1/1/2021
Any help will go a long way thanks
you can use GROUP BY with max() function.
e.g. select * from table group by rank having max(created_date)
Android SQLite version is 3.19 and doesn't support windows function like over and row_number(). I don't have any auto incremented column. I have created view using data from different table. My view details are below.
1 means in stock
2 means out stock
3 means reset count and start from given quantity.
uniquekey is unique id for each row
I want to get running total as below:
uniquekey date ProductName uniqueKeyProduct InOutType quantity runningTotal
edfrgdctydkkc 2020-06-07 Apple dheykdhr 1 10 10
edfrgdctkduxc 2020-06-08 Orange xdefrttk 1 20 20
fdfrgdctydysc 2020-06-08 Apple dheykdhr 2 5 5
3dfrgrtkvctyf 2020-06-08 Apple dheykdhr 1 2 7
ctgrteerylkdc 2020-06-09 Orange xdefrttk 2 8 12
edffjritydmnc 2020-06-10 Orange xdefrttk 3 5 5
kkdjdjrgdctyk 2020-06-10 Apple dheykdhr 3 2 2
egdhgdctyjjdc 2020-06-11 Orange xdefrttk 1 20 25
edfryrytymnbc 2020-06-15 Apple dheykdhr 1 10 12
fgeegdctydk3c 2020-06-18 Apple dheykdhr 2 2 10
hyidfhhhfd89c 2020-06-20 Orange xdefrttk 2 8 17
I don't have any auto incremented column
Assuming that you haven't defined the table using WITHOUT ROWID then you still have an equivalent column, namely the rowid column.
AUTOINCREMENT is an alias of the rowid column, it is inefficient and rarely required
You may wish to read https://www.sqlite.org/rowidtable.html
I want to get running total as below:
As the date column does not determine the insert order (e.g. 2020-06-08 2 Apple rows were processed) the rowid column has been utilised (not 100% failsafe in this regard).
You may wish to consider making the date a column that holds the date and time of the insert.
One way to accomplish the above would be to utilise a TRIGGER. Triggers are driven by an INSERT UPDATE or DELETE event. So it makes sense to use a trigger whenever a row is inserted to then set the runningtotal.
The following TRIGGER maintains the running total for the data that you have provided.
CREATE TRIGGER IF NOT EXISTS mytable_after_insert
AFTER INSERT ON mytable
BEGIN
UPDATE mytable SET runningtotal =
CASE
/* in stock */
WHEN new.inouttype = 1 THEN
COALESCE(
(
SELECT mt1.runningtotal
FROM mytable AS mt1
WHERE mt1.rowid < new.rowid AND mt1.uniquekeyproduct = new.uniquekeyproduct
ORDER BY rowid DESC
LIMIT 1
),0
)
+ new.quantity
/* out stock */
WHEN new.inouttype = 2 THEN
COALESCE(
(
SELECT mt2.runningtotal
FROM mytable AS mt2
WHERE mt2.rowid < new.rowid AND mt2.uniquekeyproduct = new.uniquekeyproduct
ORDER BY rowid DESC
LIMIT 1
),0
)
- new.quantity
/* reset */
WHEN new.inouttype = 3 THEN new.quantity
END
WHERE rowid = new.rowid
;
END
;
note that the table name mytable will likely have to be changed. Perhaps the trigger's name should be changed as well.
The following is the SQL used to test the above. It
Drops the Trigger
Drops the Table
Creates the table (this may need to be amended appropriately)
Creates the Trigger
Inserts all the rows (note that the runningtotal column defaults to 0)
Queries the resultant table showing the runningtotal and also the rowid
:-
DROP TRIGGER IF EXISTS mytable_after_insert;
DROP TABLE IF EXISTS mytable;
CREATE TABLE IF NOT EXISTS mytable
(
uniquekey TEXT PRIMARY KEY,
date TEXT,
productname TEXT,
uniquekeyproduct TEXT,
inouttype INTEGER,
quantity INTEGER,
runningtotal INTEGER DEFAULT 0
)
;
CREATE TRIGGER IF NOT EXISTS mytable_after_insert
AFTER INSERT ON mytable
BEGIN
UPDATE mytable SET runningtotal =
CASE
/* in stock */
WHEN new.inouttype = 1 THEN
COALESCE(
(
SELECT mt1.runningtotal
FROM mytable AS mt1
WHERE mt1.rowid < new.rowid AND mt1.uniquekeyproduct = new.uniquekeyproduct
ORDER BY rowid DESC
LIMIT 1
),0
)
+ new.quantity
/* out stock */
WHEN new.inouttype = 2 THEN
COALESCE(
(
SELECT mt2.runningtotal
FROM mytable AS mt2
WHERE mt2.rowid < new.rowid AND mt2.uniquekeyproduct = new.uniquekeyproduct
ORDER BY rowid DESC
LIMIT 1
),0
)
- new.quantity
/* reset */
WHEN new.inouttype = 3 THEN new.quantity
END
WHERE rowid = new.rowid
;
END
;
INSERT INTO mytable (
uniquekey,date,productname,uniquekeyproduct,inouttype,quantity /* running total not supplied so defaults to 0 */
)
VALUES
('edfrgdctydkkc','2020-06-07','Apple','dheykdhr',1,10),
('edfrgdctkduxc','2020-06-08','Orange','xdefrttk',1,20),
('fdfrgdctydysc','2020-06-08','Apple','dheykdhr',2,5),
('3dfrgrtkvctyf','2020-06-08','Apple','dheykdhr',1,2),
('ctgrteerylkdc','2020-06-09','Orange','xdefrttk',2,8),
('edffjritydmnc','2020-06-10','Orange','xdefrttk',3,5),
('kkdjdjrgdctyk','2020-06-10','Apple','dheykdhr',3,2),
('egdhgdctyjjdc','2020-06-11','Orange','xdefrttk',1,20),
('edfryrytymnbc','2020-06-15','Apple','dheykdhr',1,10),
('fgeegdctydk3c','2020-06-18','Apple','dheykdhr',2,2),
('hyidfhhhfd89c','2020-06-20','Orange','xdefrttk',2,8)
;
SELECT rowid,* FROM mytable ORDER BY rowid ASC
The result being :-
Note that if normalisation rules were followed then there should be
another table for the products and thus that the product name would
not be duplicated, all that would be needed was the uniquekeyproduct.
e.g. if a product name were changed then all rows in the mytable table would have to be updated whereas if there were a product table a name changed would be just need the 1 row to be updated and it would be reflected when querying mytable (the ProductName column would no longer be required).
COALESCE is used to convert the null returned when the first row for a product is inserted as there are no rows that match the selection criteria for in stock and out stock actions. see https://www.sqlitetutorial.net/sqlite-functions/sqlite-coalesce/
CASE ..... END is for conditional processing of the inouttype column. It has 3 WHEN clauses one for each of the types (1,2 or 3). see https://www.sqlite.org/lang_expr.html#case
In the subqueries used within the first two WHEN clauses tables are given a temporary name mt1 and mt2 respectively, using AS to ensure that there is no ambiguity as to where the data is to come from.
Note that the as 3.19 is quite old the above was tested on more recent versions so there may be some issues. You may wish to have a look through https://www.sqlite.org/changes.html if you come across issues.
I have the below table in my DB
id name is_current
1 apple 0
2 banana 1
3 mango 0
4 grapes 1
5 pineapple 1
I want to execute an update query which will update the (fruit) table last column (is_current) single value and at the same time the whole column values as well. For example the first row has an apple with id=1 and I want to set this value to 1 and all other fruit values to zero so the table look like,
id name is_current
1 apple 1
2 banana 0
3 mango 0
4 grapes 0
5 pineapple 0
Currently I am using two different queries and to different methods to achieve this
1st: is to set all values of is_current column to 0
String sql = "UPDATE "+TABLE_NAME +" SET " + is_current + " = '"+ Zero +"';
2nd: is to set the apple values to 1 by using id
String sql = "UPDATE "+TABLE_NAME +" SET " + is_current + " = '"+ One +"' WHERE "+ id + " = "+rowId;
So how can I combine these two queries to a single one to achieve this?
If you want to do this stuff for a specific fruit/ID (e.g. every time you update apples) you can set a trigger such that when you update that fruit, then it will automatically set to zero all other rows.
However if you want to do this stuff in a more general way then you need to perform 2 queries (as told by #Der Golem)
how can I combine these two queries to a single one to achieve this?
You can't.
You have to execute at least 2 commands.
A command to update all the is_current values to 0.
And a command to update the specified record to 1.
I want to retrieve rows from table having MAX(col), but MAX(col) return multiple rows if values at col has same data.
I have 2 tables as below:
**Table1**
row_id INTEGER (Primary key auto incremented),
name TEXT
**Table2**
row_id INTEGER (Primary key auto incremented),
ref_id INTEGER (Foreign key of Table1(row_id)),
date_in_long TEXT,
data TEXT
Following query I am performing to get rows having MAX(date_in_long), expecting single latest entered rows.
SELECT DISTINCT a.name, b.row_id, b.ref_id, b.date_in_long, b.data
FROM Table1 a, Table2 b
WHERE a.row_id=b.ref_id
AND b.date_in_long =
(SELECT MAX(c.date_in_long)
FROM Table2 c
WHERE c.ref_id=a.row_id
)
Output result would be perfect if date_in_long is having different values against ref_id.. but it returns multiple rows is values are same.
Example
Table1:
row_id name
1 aparna
2 user1
3 XYZ
Table2:
row_id ref_id date_in_long data
1 1 98 data1 for aparna
2 1 100 data2 for aparna
3 1 100 data3 for aparna
4 2 200 data1 for user1
5 2 300 data2 for user1
6 3 100 data1 for XYZ
Result of above query:
row_id ref_id name date_in_long data
2 1 aparna 100 data2 for aparna
3 1 aparna 100 data3 for aparna
5 2 user1 300 data2 for user1
6 3 XYZ 100 data1 for XYZ
Expected result should be:
row_id ref_id name date_in_long data
3 1 aparna 100 data3 for aparna
5 2 user1 300 data3 for user1
6 3 XYZ 100 data1 for XYZ
Please let me know how issue in above query.
Adding below condition(As solution provided by Alexandar with this post) excluding some rows
AND
b.row_id = (Select MAX(c.row_id) from Table2 c where c.ref_id = b.ref_id)
Output after adding above row_id condition:
row_id ref_id name date_in_long data
3 1 aparna 100 data3 for aparna
6 3 XYZ 100 data1 for XYZ
No rows for USER1.
Please let me know how to solve this query.
Thank you,
Regards,
Aparna
The issue is that the "distinct" keyword doesn't mean "return rows where every value is different from every other row", it means "return rows that are in some way different from each other row".
So even though row_id 2 and 3 have the same ref_id, they have a different row_id and data column- Hence, they're unique rows.
One option is to add an extra condition so that only the max row_id for a specific ref-id is respected.
The added condition would look something like this.
AND
b.row_id = (Select MAX(c.row_id) from Table2 c where c.ref_id = b.ref_id)
Following query solve my issue.
SELECT a.name, b.row_id, b.ref_id, b.date_in_long, b.data, MAX(date_in_long)
FROM Table1 a INNER JOIN Table2 b
ON a.row_id=b.ref_id
GROUP BY a.row_id
Thank you,
Regards,
Aparna
Hello I have a table with that structure:
ID VALUE
1 3
2 5
3 12
if I query select id,value,value+5 from table. Thats the result
ID VALUE NEW_VALUE
1 3 8
2 5 10
3 12 17
And what I want to make a query indicating the id and the new value that return the whole table but with a 3rd column indicating the new values after inserting. for example for myQuery(id=2,value=8)
ID VALUE NEW_VALUE
1 3 3
2 5 8
3 12 12
Is posible to do that in the same query?
YOu can use the WHERE clause to select only the rows you want ("...if the student has the given id..."):
update T
set col3 = col2 + 5
where id = 2
Of course, col3 would have to exist before you can update it. So you will either have to issue an ALTER-TABLE statement (if your implementation supports it) or recreate the table with the desired columns, import the original data (INSERT INTO YOURNEWTABLE...SELECT ... from YOUROLDTABLE) and then update col3.
If you don't want to "persist" this third column but only need it to be displayed when you query:
select id, col2, col2 + 5 as myComputedValue
from T
where id = 2
Finally, if you want to display all rows but change the addend conditionally (add zero to col2 when the id is not one of the ones you desire but add 5 when it is) then you can use the CASE statement.