Android SQLite: combine multiple rows into one - android

I have two SQLite tables:
- users:
id username age
1 jack 24
2 lisa 19
- images:
id username image
1 jack jackImg1.jpg
2 jack jackImg2.jpg
3 lisa lisaImg1.jpg
I use LEFT JOIN to get all jack's images:
SELECT users.*, images.image FROM users
LEFT JOIN images ON images.username = users.username
WHERE users.username = 'jack';
the result is like this:
id username age image
1 jack 24 jackImg1.jpg
1 jack 24 jackImg2.jpg
But I'd like to get a result like this:
id username age image1 image2
1 jack 24 jackImg1.jpg jackImg2.jpg
How can I achieve a result like above table?
Note: the number of images can vary from zero to any number(like 15, 20,...)

SQLite does not provide such functionality to pivot or unpivot tables.
What you can do is group by user and use the group_concat() aggregate function to achieve a similar result:
SELECT
u.id, u.username, u.age,
group_concat(i.image, ' ') images
FROM users u LEFT JOIN images i
ON i.username = u.username
WHERE u.username = 'jack'
GROUP BY u.id, u.username, u.age
I used space as a separator between the images, you can use any char you want.
See the demo.
Results:
| id | username | age | images |
| --- | -------- | --- | ------------------------- |
| 1 | jack | 24 | jackImg1.jpg jackImg2.jpg |

Related

How to get rows from same table with different conditions

I want to get data from same table with different conditions. I am using sqlite in android studio.
**ID Name Role**
1 Emma Manager
2 Olivia Manager
3 Ava Manager
4 Isabella Sales officer
5 Sophia Sales Officer
6 Charlotte Sales Officer
7 Mia Clerk
8 Amelia Clerk
Assume this table, I have different types of roles and different numbers of persons in a role. I want to select 2 persons from each role.
Select * from employeeTable where role = 'Manager' LIMIT 2
Select * from employeeTable where role = 'Sales officer' LIMIT 2
Select * from employeeTable where role = 'Clerk' LIMIT 2
Simply I want to join the result of these three queries.
Sorry if the childish question. And thanks in advance
With row_number() window function:
select t.id, t.name, t.role
from (
select *, row_number() over (partition by role) rn
from employeeTable
) t
where t.rn <= 2
You can also define:
partition by role order by name
or:
partition by role order by id
instead of just:
partition by role
to get specific rows in the results.
See the demo.
Results:
| ID | Name | Role |
| --- | -------- | ------------- |
| 7 | Mia | Clerk |
| 8 | Amelia | Clerk |
| 1 | Emma | Manager |
| 2 | Olivia | Manager |
| 4 | Isabella | Sales Officer |
| 5 | Sophia | Sales Officer |
Try is query and check if working:
Select * from employeeTable where role = 'Manager' LIMIT 2
UNION ALL
Select * from employeeTable where role = 'Sales officer' LIMIT 2
UNION ALL
Select * from employeeTable where role = 'Clerk' LIMIT 2

Alternatives to LEAD and LAG in SQLite

I need to find an alternative to LAG and LEAD for finding the previous and next entry in my table in SQLite since those are not support in the version used (updating is not an option).
But I also cant use the value I order by, since it can be a date and therefore can be identical on multiple entries.
Since the table has to be sorted by date, using the ID isn't an option either.
It'd be great if someone knew an alternative way of dealing with this issue, since after more than an hour of searching and trying I am out of ideas.
Edit:
The important columns to my use case are:
_id booking_date
1 2017:11-21
3 2017:11-21
4 2017:11-21
5 2017:11-21
2 2017:11-22
6 2017:11-22
7 2017:11-22
...
_id is the primary key.
The bookings need to be sorted by date.
It is possible for multiple bookings to have the same date.
Bookings with the same date are sorted by their ids (See id 2, 6 and 7 in the give n example)
I need a way to query the entry before and after an entry by its id.
For example for _id=6 the I need a query that selects the row with _id=2 and a query that selects the row with _id=7.
Alternatively a query single query that selects both will work just as good.
I do not need you to provide an entire query, but rather an approach to this issue.
Try something like that, this retrieves previous and next id of a given record using your sort order (by date+id) - assumming that id is the primary key, you can retrieve other columns od prev-next records using these ids:
SELECT *,
(SELECT id FROM t t1
WHERE t1.booking_date < t.booking_date
OR t1.booking_date = t.booking_date AND t1.id < t.id
ORDER BY booking_date DESC, ID DESC LIMIT 1 ) prev_id,
(SELECT id FROM t t1
WHERE t1.booking_date > t.booking_date
OR t1.booking_date = t.booking_date AND t1.id > t.id
ORDER BY booking_date , ID LIMIT 1 ) next_id
FROM t
order by booking_date, id
Demo: http://www.sqlfiddle.com/#!5/17631/2
| id | booking_date | prev_id | next_id |
|----|--------------|---------|---------|
| 1 | 2017-11-21 | (null) | 3 |
| 3 | 2017-11-21 | 1 | 4 |
| 4 | 2017-11-21 | 3 | 5 |
| 5 | 2017-11-21 | 4 | 2 |
| 2 | 2017-11-22 | 5 | 6 |
| 6 | 2017-11-22 | 2 | 7 |
| 7 | 2017-11-22 | 6 | (null) |
If the table looked like this, the final select would be fairly trivial.
_id booking_date seq
1 2017:11-21 1
3 2017:11-21 2
4 2017:11-21 3
5 2017:11-21 4
2 2017:11-22 1
6 2017:11-22 2
7 2017:11-22 3
seq being the number of rows in the same booking_date with smaller id. You could create a virtual view with this structure to drive the main select.
This is a possible approach. Since you were not soliciting "an entire query", I leave it up to you how to implement this idea.

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

Does TEXT datatype will limit the length ?

I'm using TEXT datatype in MySQL. But when I check the column, I only see fndjdjjj jdjejcdjj sekifkj sjkedkjfj sjekkcjej jwj.... After jwj, it suppose to have another text, but I get ...Why would this happened ? I thought TEXT can have unlimited size ?
I'm using android , and connecting with MySQL PHP.
Use LONGTEXT.
Following are the limits
Type | Maximum length
-----------+-------------------------------------
TINYTEXT | 255 (2 8−1) bytes
TEXT | 65,535 (216−1) bytes = 64 KiB
MEDIUMTEXT | 16,777,215 (224−1) bytes = 16 MiB
LONGTEXT | 4,294,967,295 (232−1) bytes = 4 GiB
TINYTEXT is limited to 255 bytes. Note the truncation during insert. Note that the data is intact after the ALTER. Note that I used MODIFY, not CONVERT TO.
mysql> CREATE TABLE so35474581 ( t TINYTEXT CHARACTER SET latin1 );
Query OK, 0 rows affected (0.24 sec)
mysql> INSERT INTO so35474581 (t) SELECT repeat('x', 444);
Query OK, 1 row affected, 1 warning (0.04 sec)
Records: 1 Duplicates: 0 Warnings: 1
mysql> SHOW WARNINGS;
+---------+------+----------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------+
| Warning | 1265 | Data truncated for column 't' at row 1 |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT LENGTH(t), CHAR_LENGTH(t) FROM so35474581;
+-----------+----------------+
| LENGTH(t) | CHAR_LENGTH(t) |
+-----------+----------------+
| 255 | 255 |
+-----------+----------------+
1 row in set (0.00 sec)
mysql> ALTER TABLE so35474581 MODIFY t LONGTEXT CHARACTER SET latin1;
Query OK, 1 row affected (0.31 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT LENGTH(t), CHAR_LENGTH(t) FROM so35474581;
+-----------+----------------+
| LENGTH(t) | CHAR_LENGTH(t) |
+-----------+----------------+
| 255 | 255 |
+-----------+----------------+
1 row in set (0.00 sec)
The CONVERT TO mentioned has to do with changing character sets.
When inserting anything over a few MB, you may have trouble with packet_size or other settings.

Sql query for filtering data with WHERE clause on same column

I have to tables:
Table A
id | title
1 | toto
2 | tata
3 | titi
Table B
id | title_id | tag_id
1 | 1 | 6
2 | 1 | 16
3 | 1 | 26
4 | 2 | 6
5 | 2 | 7
6 | 2 | 16
7 | 3 | 2
8 | 3 | 1
9 | 3 | 16
(Sorry for the bad table display)
In my application I have a tag listview with checkboxes, and when the user clicks a checkbox, I want to filter the titles with the clicked checkboxes:
(E.g: if user clicks tag 16, I should have title 1, 2 and 3 displayed. But if user clicks tag with id 26 AND tag with id 16, as result I should have only title with id 1)
I thought to a query like that:
SELECT DISTINCT A.title , A.id
FROM A
INNER JOIN B
ON B.title_id = A.id
WHERE B.tag_id = 26 AND B.tag_id = 16;
but obviously the last part of the query (two AND clause on a same column) is wrong, and I do not find a query which will give me this result.
I tried this :
SELECT DISTINCT A.title , A.id
FROM A
INNER JOIN B
ON B.title_id = A.id
WHERE B.tag_id IN ( '26', '16');
but the IN clause is like a OR clause, and as result, I get all the rows for value 26 plus all the rows for value 16 (title 1, 2 and 3) and not ONLY title 1.
I absolutely need to do this with and sql query because I'm using a SimpleCursorAdapter in order retrieve the datas and to fill an other listview.
I searched for a while, but I didn't find any relevant solution. (Or maybe I typed the wrong words...)
Do you have solution for me please?
PS: I hope I've been clear. Sorry for my bad english.
Use subqueries:
SELECT DISTINCT A.title, A.id FROM A WHERE
A.id IN (SELECT DISTINCT B.title_id FROM B WHERE B.tag_id='16')
AND A.id IN (SELECT DISTINCT B.title_id FROM B WHERE B.tag_id='26')

Categories

Resources