Table rows as columns? - android

I have the following two tables and the second one containts a dynamic amount of attributes for each entry of the first table:
people:
_id | name | first | status
----------------------------------
1 | Smtih | Sam | on
2 | Doe | Joe | off
constraints: some people may have no more than in people, some may have 20:
_id | persid | type | value
-------------------------------------------------
1 | 2 | IQ | 90
2 | 2 | bold | yes
... | ... | ... | ...
So as a intermediate result I would like to get this:
_id | name | first | status | IQ | bold | ...
------------------------------------------------ ... more depending on person
2 | Doe | Joe | off | 90 | yes | ...
so that I can eventually select those items with specific attributes e.g.:
`SELECT * FROM <--the above table--> WHERE status = 'off' AND IQ > '75'
I would be fine if those people who do not have the right attributes (in this case IQ) would not even show up in the intermediary table (quicker?).
Sadly, I did not get very far in my own feeble attempts. I guess GROUP_CONCAT should play a role, but can't get it to work.
As always, thank you guys in advance for your time and effort!

As Selvin wrote, if you know all of the types, you can generate a query. But if you add the attributes by the time, you need two queries. The last part in the following code containing the IQ will not work, because IQ is not a column.
SELECT * FROM <--the above table--> WHERE status = 'off' AND IQ > '75'
First of all, you need to get the fixed information.
SELECT _id, name, first, status ...
There you can do your selection (for example by IQ):
SELECT _id, name, first, status FROM wherever WHERE (SELECT value FROM attributes WHERE persid = _id AND type='IQ') > 75
Finally, for each of the selected records you need to get the attributes.
SELECT value FROM attributes WHERE presid=_id_given_by_program

Related

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

Selecting from a table based on relationships which are saved in another table

My Situation
I am using SQLite on Android to store some data. This data is all in the same table, but each row can have one or more relationships to other rows in that same table. These relationships are saved in another table. Think of it like this:
In Table 1 may be a row with id 0 which has 2 children with the ids 1 and 2. Both of those children will again be saved in table 1, but in table 2 there will be a mapping for each of those children from the id 0 to their own id. The tables may look something like this:
+---------------------------+
| Table 1 |
+------+------+------+------+
| ID | .... Data .... |
+------+------+------+------+
| 0 | ... | ... | ... | <--- This would be the parent of rows 1 & 2
| 1 | ... | ... | ... | as indicated in the other table
| 2 | ... | ... | ... |
| 3 | ... | ... | ... |
+----------------------------+
| Table 2 |
+-------------+--------------+
| Parent ID | Child ID |
| 0 | 1 | <-- This means that row 0 has
| 0 | 2 | <-- 2 children with the ids 1 and 2
| 2 | 5 |
| 3 | 2 | <-- Each row can have multiple parents and/or children
What I want to do essentially is select from table 1 with some arbitrary where clause and if this where clause for example matches row 0, I also need to select the children of row 0 along with it and the children of those children and so on. Since I generally suck at explaining things let me illustrate this again:
If I were to run a select like this:
SELECT * FROM TABLE1 WHERE ...
I would get a result like this:
+------+------+------+------+
| ID | .... Data .... |
+------+------+------+------+
| 0 | ... | ... | ... |
| 3 | ... | ... | ... |
But what I would like to get is this:
+------+---------+------+------+------+
| ID | isChild | .... Data .... |
+------+---------+------+------+------+
| 0 | 0 | ... | ... | ... | <--- This row along with row 3 is what actually matches the where clause
| 1 | 1 | ... | ... | ... |
| 2 | 1 | ... | ... | ... |
| 5 | 2 | ... | ... | ... |
| 3 | 0 | ... | ... | ... | <--- This row along with row 0 is what actually matches the where clause
| 2 | 1 | ... | ... | ... |
| 5 | 2 | ... | ... | ... |
Only row 1 and 3 actually match the where clause. The order of the children is not important but they should follow right after the parent and the "isChild" column would be used to indicate whether the row is a child and to what it is a child.
Notice the third row from the top in the output above, the one with the id 2. It has 2 in "isChild" because it is a child of the row above which also is a child. You can think of the whole output above as a tree like this:
- 0
- 1 <-- 1 is a child of 0
- 2 <-- 2 is a child of 0
- 5 <-- 5 is a child of 2
- 3
- 2 <-- 2 is a child of 3
- 5 <-- 5 is a child of 2
The "isChild" column essentially tells you on which level of the tree you are.
The Problem
Up until now I had implemented this with multiple selects. I would first select the rows from table1, take the ids from each row and then select the mappings for each row from table2. With those mappings I would select the children from table1 and after that I would again look for mappings of the children in table2 and so on. It doesn't take a genius to see that this can cause huge performance problems very quickly and it indeed was pretty slow.
I have since then been trying to improve this by reducing the number of selects required but now I have hit a wall. I have implemented any sort of improvement I can think of and it works for the most part but if you are dealing with big datasets everything slows down exponentially and I don't see any other way I could improve this in code. I started thinking and came to the conclusion that if I could somehow select everything at once in the manner I described above it would solve a whole slew of problems for me.
My attempts to solve the problem so far
Since I cannot improve this further in code I have turned my attention to SQL. I have already made many unrelated improvements which resulted in great performance gains by implementing triggers to do the most common tasks like creating and deleting the mappings in table2. And I have been hoping I can also solve this problem in a similar manner.
I have tried all sorts of JOINs or UNIONs but nothing seems to work as I expect it. I have a feeling I might be going about this all the wrong way. I haven't event attempted to include a "isChild" column up until now.
This is a link to the SQLFiddle I use to test my selects
When I started working on this I foolishly thought that a simple JOIN would solve the problem but I am doubting that at this point and I am also not sure if what I want to do is even possible (in an efficient manner).
This problem has made me realise how little I know about SQL and if some SQL wizard could come along and tell me how simple the solution actually is I would very much appreciate it! (Although I suspect that the solution to my problem isn't actually that simple)
Please keep in mind that this question is talking specifically about SQLite on Android. But I tried to make this question as general as possible since it is also applicable for many other SQL implementations or operating systems.
If you have a really great answer to this question with a simple solution that blows my mind and a great explanation to go along with then I won't hesitate to reward you with a bounty.
To read the children recursively, you would have to use a recursive common table expression.
However, this was introduced in SQLite 3.8.3, so your Android device is very unlikely to support it.
You have to keep using multiple queries, or to use your own version of SQLite with the NDK.

Designing a structured database to chat, One table or more than one table

Good afternoon ,
I'm thinking about how it would be best to keep posts sqlite table 1 or more than 1,
To take an example, a chat , which is better to keep it all in 1 - same table (if you can ) or better in different ?
(Example 1 table )
http://cmanios.wordpress.com/2013/10/29/read-sms-directly-from-sqlite-database-in-android/
I think if we have all the information in a table will be easier information overflow ( stack overflow )
Limitations on android sqlite tables: (related topics)
Maximum SQLite Database Size in Android Application
SQLite database limits in Android
I mean I can include more message all in one table .
From my point of view , as a programmer , I want to create more than one table.
Example 1 and x tables :
( 1 table ) (Where user = "select " ) Only need see specific user, for example "messages of user 1 and 2)
Table : (User 1 + user 2 + user3 ... userx)
+-----------------------------------------------------------------------------------------------------------------+
| date | date_sent | person | body |
|------------------------------------------------------------------------------------------------------------------
| 2013-10-20 13:48:18 | 2013-10-20 13:48:16 | User1 | Hello Christos! How are you? |
| 2013-10-20 16:34:03 | 1970-01-01 02:00:00 | User2 | Fine, thanks ! I configure the left MFD of a F-16 jet |
| 2013-10-20 16:40:02 | 2013-10-20 16:40:01 | User3 | Awesome! I am throwing a party tomorrow at 21:45! |
| 2013-10-20 17:15:15 | 1970-01-01 02:00:00 | Userx | Thanks! I will be there! |
+-----------------------------------------------------------------------------------------------------------------+
- (2 or more tables) easy select all table
+-----------------------------------------------------------------------------------------------------------------+
| date | date_sent | person | body |
|------------------------------------------------------------------------------------------------------------------
| 2013-10-20 13:48:18 | 2013-10-20 13:48:16 | User1 | Hello Christos! How are you? |
| 2013-10-20 16:34:03 | 1970-01-01 02:00:00 | User2 | Fine, thanks ! I configure the left MFD of a F-16 jet |
| 2013-10-20 16:40:02 | 2013-10-20 16:40:01 | User1 | Awesome! I am throwing a party tomorrow at 21:45! |
| 2013-10-20 17:15:15 | 1970-01-01 02:00:00 | User2 | Thanks! I will be there! |
+-----------------------------------------------------------------------------------------------------------------+
+-----------------------------------------------------------------------------------------------------------------+
| date | date_sent | person | body |
|------------------------------------------------------------------------------------------------------------------
| 2013-10-20 13:48:18 | 2013-10-20 13:48:16 | User1 | Hello Christos! How are you? |
| 2013-10-20 16:34:03 | 1970-01-01 02:00:00 | User3 | Fine, thanks ! I configure the left MFD of a F-16 jet |
| 2013-10-20 16:40:02 | 2013-10-20 16:40:01 | User1 | Awesome! I am throwing a party tomorrow at 21:45! |
| 2013-10-20 17:15:15 | 1970-01-01 02:00:00 | User3 | Thanks! I will be there! |
+-----------------------------------------------------------------------------------------------------------------+
.
.
.
.
I believe appropriate, create more than one table , we will not have storage problems , all in a single table.
Someone could tell me which is the best way? or if I'm wrong concepts
The links you provide for size limits in sqlite both indicate that this shouldn't really be an issue.
If you really think you're going to reach:
http://www.sqlite.org/limits.html
The theoretical maximum number of rows in a table is 264
(18446744073709551616 or about 1.8e+19). This limit is unreachable
since the maximum database size of 140 terabytes will be reached
first. A 140 terabytes database can hold no more than approximately
1e+13 rows, and then only if there are no indices and if each row
contains very little data.
On an android device...well I think maybe you need to reconsider the topic a bit.
The next question:
Should you be creating/dropping tables on the fly? This is a pretty bad idea - it's prone to causing weird problems. I'm not saying you CAN'T do it, but it's not a normal way to do this kind of thing.
Personally - one database. If you really feel like you need to break it up, a rough way to do it might be something like:
MyDatabase:
tables: fields
user UserUuid,name,
message UserUuid,MessageId,MessageText,to, from, timestamp
attachments MessageId,AttacmentId,AttachmentContent
This would allow you to create new users and link them to messages and attachments while keeping things organized better than all being in one table, and would avoid you creating/destroying tables on the fly. You can probably find an organizational chart which better suits your specific needs, but this should get you rolling.

About the efficient query for displaying on ListView

I'm a beginner of SQL.
I would like to display sqlite data on Android listview. The table has the following structure.
| _id | name | data | ...
---------------------
| 0 | A | abc |
| 1 | B | def |
| 2 | C | ghi | ...
| 3 | D | jkl |
| 4 | E | mno |
So, when the user inputs [C, B, D], I want to display name and data column in user's order.
For example,
ListView
---------------------
C ghi
---------------------
B def
---------------------
D jkl
---------------------
I'm torn between using ArrayAdapter and CursorAdapter now.
Should I do SELECT 3 times, store values in array, and use ArrayAdapter? Or, can fulfill my demands with SELECT once?
Thanks in advance.
It'll be a bit complicated but it can be done in a single query.
SELECT * FROM yourTable
ORDER BY
CASE name
WHEN 'C' THEN 0
WHEN 'B' THEN 1
WHEN 'D' THEN 2
END
You'll have to construct the query according to the user input ofcourse
.
Look more here
You can fulfill your demands with SELECT query. Your query would look like:
String query = "SELECT * FROM yourTable WHERE name IN ('C', 'B', 'D');"

Many-to-Many Query in One Cursor Without Repeating Data

So, I'm going to say that I have three tables as follows:
POSTS POSTS_TAGS TAGS
+-----+-----------+ +---------+--------+ +-----+-------+
| _id | title | | post_id | tag_id | | _id | title |
+-----+-----------+ +---------+--------+ +-----+-------+
| 0 | foo | | 0 | 1 | | 0 | baz |
+-----+-----------+ +---------+--------+ +-----+-------+
| 1 | bar | | 0 | 2 | | 1 | quux |
+-----+-----------+ +---------+--------+ +-----+-------+
| 1 | 0 | | 2 | corge |
+---------+--------+ +-----+-------+
| 1 | 2 |
+---------+--------+
Is there any way to formulate a query with SQLite such that I could then have a cursor with the following data in it:
row1 = <foo, <quux, corge>>
row2 = <bar, <baz, corge>>
As opposed to:
row1 = <foo, quux>
row2 = <foo, corge>
row3 = <bar, baz>
row4 = <bar, corge>
However, I severely doubt that there is anything that will give me precisely that, so I guess my real question is, what is the best way to formulate a query such as this, so that I can pass it back to my activity, and it would be able to return all this data to the activity? Or am I really going to need to iterate through my cursor again afterwards to "pick up" all the extra data and reorganize it myself.
Got the solution:
SELECT posts._id, posts.title, GROUP_CONCAT(tags._id) AS tags_id, GROUP_CONCAT(tags.tag_name) AS tags_name FROM posts
LEFT OUTER JOIN posts_tags ON posts_tags.post_id=posts.post_id
LEFT OUTER JOIN tags ON posts_tags.tag_id=tags.tag_id
GROUP BY posts._id;
Please adapt the query to your problem :)
You can find SQLite documentation about concat(x) and concat(x,separator) here.
Anyway you can also follow my problem on google group.

Categories

Resources