Android Studio - Room query different result than expected - android

I'm having a difficult time understanding why does the same query on the same database is correct on my local testing environment (my computer) and is wrong over my device/emulator.
The database is literally the same (copied from emulator to computer).
SELECT * FROM (
SELECT name, max(date_col) as date_col, value FROM tbl
WHERE date_col <= '2021-06-30'
GROUP BY name
UNION
SELECT name, min(date_col) as date_col, value FROM tbl
GROUP BY name
ORDER BY date_col DESC
)
GROUP BY name
The schema for the table is (id, date_col, name, value).
What I'm trying to do is select all the rows with the nearest date to the supplied date. I'm not quite sure that this is the best way of doing it so any suggestions are welcomed
When trying this query in my computer (SQLITE v3.27.2) it works as intended and when testing on a device/emulator (Tried multiple API levels such as 23, 27, 28) they all failed.
Edit:
Table data:
|name |date_col |value|
|-----|----------|-----|
|NAME6|2021-06-29|71 |
|NAME7|2021-06-29|80 |
|NAME1|2021-06-29|2925 |
|NAME4|2021-06-29|182.0|
|NAME2|2021-06-29|365 |
|NAME3|2021-06-29|81.0 |
|NAME5|2021-06-29|0.25 |
|NAME7|2021-06-27|81.0 |
|NAME1|2021-06-27|3000 |
|NAME5|2021-06-01|0.35 |
|NAME6|2021-06-01|68.0 |
|NAME5|2021-06-28|0.15 |
Results on device (for date 2021-06-28):
|name |date_col |value|
|-----|----------|-----|
|NAME1|2021-06-27|3000 |
|NAME2|2021-06-29|365.0|
|NAME3|2021-06-29|81.0 |
|NAME4|2021-06-29|182.0|
|NAME5|2021-06-01|0.35 |
|NAME6|2021-06-01|68.0 |
|NAME7|2021-06-27|81.0 |
Results on computer (for date 2021-06-28):
|name |date_col |value|
|-----|----------|-----|
|NAME1|2021-06-27|3000 |
|NAME2|2021-06-29|365.0|
|NAME3|2021-06-29|81.0 |
|NAME4|2021-06-29|182.0|
|NAME5|2021-06-28|0.15 |
|NAME6|2021-06-01|68.0 |
|NAME7|2021-06-27|81.0 |
As you can see, in this example the difference is with name5, it should be 0.15 but on device for some reason its 0.35.
What could be the reason for these differences?
Thank you very much!

SQLite allows statements with SELECT * and GROUP BY, but the resulting rows are arbitrary.
If you want to use this in lower API levels, you can't use window functions which would easily solve the problem like this:
SELECT name, date_col, value
FROM (
SELECT *, ROW_NUMBER() OVER (
PARTITION BY name
ORDER BY date_col < '2021-06-28' DESC,
abs(strftime('%s', date_col) - strftime('%s', '2021-06-28'))
) rn
FROM tbl
)
WHERE rn = 1
ORDER BY name;
You can use a correlated subquery:
SELECT t1.name, t1.date_col, t1.value
FROM tbl t1
WHERE t1.date_col = (
SELECT t2.date_col
FROM tbl t2
WHERE t2.name = t1.name
ORDER BY date_col < '2021-06-28' DESC,
abs(strftime('%s', t2.date_col) - strftime('%s', '2021-06-28'))
LIMIT 1
)
ORDER BY name;
See the demo.

Related

Unnest (or similar) in SQLite

I'd like to return multiple rows as a single row to be handled by an Android Cursor Adapter.
I currently have a table with a date column and I'd like to return, as a single row, all the rows that have the same date.
Consider the following table:
ID | Name | Date
-------------------------------
1 | 'Mark' | '08/06/15'
2 | 'Peter' | '08/06/15'
3 | 'Henry' | '08/06/15'
4 | 'Bob' | '17/04/16'
5 | 'Tony' | '23/08/13'
6 | 'Tim' | '17/04/16'
I'd like to query the results as follows:
Date | Names
------------------------------------
'08/06/15' | 'Mark, Peter, Henry'
'17/04/16' | 'Bob, Tim'
'23/08/13' | 'Tony'
Using this link I was able to obtain the following query:
SELECT t1.id, GROUP_CONCAT(t1.Name ) AS Names
FROM Table1 t1 JOIN Table2 t2 ON t1.ID = t2.ID
GROUP BY t1.ID;
However, since all the data is from the same table, and I know the dates to query in advance, I was hoping to use JOIN with an inputted array and have SQLite parse it (ie. like unnest in Postgres) as if it came from an actual table.
The array would be something like:
['08/06/15', '17/04/16', '23/08/13', '09/08/18']
This can probably also be done by nesting SQL queries, but I'd like an optimized solution if possible.
SQLite has no array type.
The simplest way would be to use the IN operator:
SELECT ID, group_concat(Name) AS Names
FROM MyTable
WHERE Date IN ('08/06/15', '17/04/16', '23/08/13', '09/08/18')
GROUP BY ID;
If you really want to use a join, you can construct a virtual table with a VALUES clause (in Android Jelly Bean or later), or a compound query:
SELECT ID, group_concat(Name) AS Names
FROM MyTable
JOIN (VALUES('08/06/15'), ('17/04/16'), ('23/08/13'), ('09/08/18'))
ON Date = column1
GROUP BY ID;
SELECT ID, group_concat(Name) AS Names
FROM MyTable
JOIN (SELECT '08/06/15' AS Date UNION ALL
SELECT '17/04/16' UNION ALL
SELECT '23/08/13' UNION ALL
SELECT '09/08/18' ) USING (Date)
GROUP BY ID;
Is this what you want:
SELECT Date, group_concat(Name) AS Names
FROM table_name
GROUP BY Date;

Is it possible to take column names for sqlite database as input from user in an android app?

I am creating an android app for my college faculties through which they will be able to keep and maintain the attendance of students in their lectures.
I thought of designing the database this way
Date | Student1 | Student2 | . . . . . . |. . .|. . . | Student60
In this structure each INSERT INTO statement will take 61 values, one for the date and rest for presence/absence record of 60 students.
But in this case the column headers have to be named by the user(the column header should be unique identifier for that particular student, like his roll no.). Is it possible? or am I completely on the wrong track?
Please suggest if there is a better database design alternative.
I also need to provide the users the ability to retrieve aggregate attendance % of a student.
Apologies in advance if I've asked something very basic or stupid.
This is on the wrong track. Instead, make the student's ID a primary key column, and use the other columns for storing student metadata, something like this:
Students
ID | first_name | last_name |
1 | Jon | Skeet |
2 | Gordon | Linoff |
...
Attendance
ID | SID | date | status
1 | 1 | 2017-05-24 | absent
2 | 1 | 2017-05-25 | present
3 | 2 | 2017-05-24 | present
4 | 2 | 2017-05-25 | present
Now if you wanted to find out which students were present on a given day you could use the following query:
SELECT
s.first_name,
s.last_name
FROM Students s
INNER JOIN Attendance a
ON s.ID = s.SID
WHERE a.status = 'present' AND
a.date = '2017-05-24'
Note that in practice you might use an integer (0 or 1) to store the attendance.
Towards answering your actual question, if you wanted a summary by student along with his attendance record in percent over the most recent 90 days, you could use this:
SELECT SID, 100*(SUM(CASE WHEN status = 'present' THEN 1 ELSE 0 END) / 90) AS p_attedance
FROM Attendance
WHERE date > date('now', '-90 days');
GROUP BY SID

Sqlite Distinct Query From -To, To - From

I have following data:
me = my_userid;
Table: Message
message_id | message_from | message_to
1 | me | user
2 | user | me
Running query gives two rows (SELECT DISTINCT message_from,message_to FROM Message WHERE message_from ='"+me+"' OR message_to ='"+me+"'");
Used OR because my id can be in from(when sending) or in TO (when other user sends me message)
-- This returns two rows however i want it to return one row because if you switch to - from you get same ids, So how can this be done in the query. Thanks
You can use min() and max() as scalar functions:
select distinct min(message_from, message_to) as m1, max(message_from, message_to) as m2
from message
where message_from ='"+me+"' OR message_to ='"+me+"'"
These are equivalent to least() and greatest() in other databases.

SQLite union columns

My problem
I am actually developing an SQLite database for an android application. I come from MySQL, where the query I'll expose works nicely.
This is my database structure:
table1: mid int(1) primary key autoincrement, name varchar(256)
table2: aid int(1) primary key autoincrement, name varchar(256)
With data inserted:
table1, row1: 1, "abc"
table2, row1: 1, "def"
What I want to do
I want to do a union so that the resulting data is:
| mid | aid | name |
--------------------
| 1 | 0 |"abc" |
| 0 | 1 |"def" |
So, I came up with this simple query:
select mid, name, 0 as aid from table1 union select aid, name, 0 as mid from table2;
However, I'm getting this back:
| mid | name | aid |
--------------------
| 1 |"abc" | 0 |
| 1 |"def" | 0 |
(I don't mind the column order)
This is of course not what I am looking for, and I can't see what I am doing wrong.
Any help will be appreciatted.
Thank you.
Maybe it's the column order that's tripping it up?
How about
select mid, 0 as aid, name from table1 union select 0 as mid, aid, name from table2;
works for me, at least on SQLFiddle: http://sqlfiddle.com/#!2/157f09/1

[SQLite Query]: build tab with 0 values

I'm trying to realize a query but I don't know how to built it.
My tabs is something like this:
date, type_fruit, price
and records are something like this:
date_1, orange, 10$
date_1, orange, 5$
date_2, peach, 3$
date_3, banana, 25$
date_3, apple, 10$
My goal is build a tab like this:
| ---------------------------------------
| | orange | banana | apple |
| date_1 | 15$ | 0$ | 0$ |
| date_3 | 0$ | 25$ | 10$ |
|----------------------------------------
but...but...taking just top 3 bought fruits!
So, taking from SQLite DB just orange (10$+5$), banana (25$) and apple(10$) and not taking peach (only 3$).
Could anyone help me please?
PS: I hope I explained my problem in a clear way, sorry for some english mistake.
This is example for SQL SERVER.
IF you use another DB maybe will be chages.
if OBJECT_ID('tempdb..#example') IS NOT NULL
drop table #example
go
create table #example
(
[date] date,
type_fruit varchar(100),
price int
)
insert into #example
select
getdate() as [date], 'orange' as type_fruit, 10 as price
union select
getdate(), 'orange', 5
union select
getdate()-1, 'peach', 3
union select
getdate()-2, 'banana', 25
union select
getdate()-2, 'apple', 10
SELECT [DATE], ISNULL(orange,0)orange, ISNULL(banana,0)orange,ISNULL(apple,0)orange
FROM (
SELECT [date], type_fruit, price
FROM #example) up
PIVOT (SUM(PRICE) FOR type_fruit IN ( orange, banana,apple)) AS pvt
WHERE isnull(orange,-1)+isnull(banana,-1)+ISNULL(apple,-1) <> -3
GO
I hope this is will hekp you.

Categories

Resources