How do I organize this information in SQLite? - android

I am creating an application and using SQLite for a database, but I never used a database class.
I'm trying to figure out how to organize the following information:
A User Class: Has a name, two integer fields, and a LIST of groups,
A Group class: Has a name, a double field, and a LIST of users
A user will also eventually have to have some sort of authentication
(username/password) field but I plan to deal with that later.
If you could help me think through how to organize this information in SQLite, that would be great.

Tables can be organised as follows,
Table User_tbl
--------------------------------------------------
_ID int primary key
--------------------------------------------------
name text name of user
--------------------------------------------------
field1 int int field 1
--------------------------------------------------
field2 int int field 2
--------------------------------------------------
Table Group_tbl
--------------------------------------------------
_ID int primary key
--------------------------------------------------
name text name of group
--------------------------------------------------
field double double field
--------------------------------------------------
As per #cricket_007s answer, you need another table that links both these fields,
Table User_groups_tbl
--------------------------------------------------
_ID int primary key
--------------------------------------------------
user_id int _ID value from User_tbl
--------------------------------------------------
group_id int _ID value from Group_tbl
--------------------------------------------------
A INNER JOIN query like,
SELECT User_tbl._ID, User_tbl.name, Group_tbl._ID, Group_tbl.name, User_groups_tbl.user_id, User_groups_tbl.group_id
FROM User_tbl, Group_tbl, User_groups_tbl
INNER JOIN User_tbl.User_tbl._ID ON User_groups_tbl.User_groups_tbl.user_id
INNER JOIN Group_tbl.Group_tbl._ID ON User_groups_tbl.User_groups_tbl.group_id
WHERE User_groups_tbl.user_id = user_id;
will yield all groups in the user is in.
Likewise an INNER JOIN query like,
SELECT User_tbl._ID, User_tbl.name, Group_tbl._ID, Group_tbl.name, User_groups_tbl.user_id, User_groups_tbl.group_id
FROM User_tbl, Group_tbl, User_groups_tbl
INNER JOIN User_tbl.User_tbl._ID ON User_groups_tbl.User_groups_tbl.user_id
INNER JOIN Group_tbl.Group_tbl._ID ON User_groups_tbl.User_groups_tbl.group_id
WHERE User_groups_tbl.group_id = group_id;
will yield all users in the a group.
Explanation for User_groups_tbl
This table is used to store the many-to-many relationship between the two tables User_tbl and Group_tbl. When a user is added to a new group or vice versa, add an entry with the _ID of the corresponding group and the _ID of the corresponding user in this table.

As far as i understand, the two tables form a many-many relationship. So, a "good" database design would have 3 tables.
Table 1(User): user_ID(primary key), name, field_1, field_2
Table 2(Group): group_ID(primary key), name, double_Field
Table 3(Relationship): user_ID(foreign key), group_ID(foreign key).

If I understood the question correctly , you need to deal with the many-many relationship between user and group. With SQLite its really difficult to handle that kind of relation.
I recommend you to use android ORM for that such as Realm Android which is faster than sqlite and perfect for your need. For many-many relationship, make your models as https://realm.io/docs/java/latest/#many-to-many

You could go to Codecademy and take the SQL course. Or you could use Realm or Cupboard or ActiveAndroid (there's several libraries to ease SQLite development). And, unless you are familiar with writing SQL code, then it's best to use one of those.
Basically, you'll have a User table, Group table, then a UserGroup lookup table (2 columns) that lists the ID values of which user ids belong to which group ids.
This can be seen as a many-to-many relationship.

Related

Is it possible to create a table in the Room without a primary key?

I have a table in MySql and I named it FAQs and inside the table, There are two columns, Question column and Answer column, I want to get the data who inside the FAQs table and store it in the offline database but I got this message An entity must have at least 1 field annotated with #PrimaryKey
The Table
#Entity(tableName = "FAQs")
public class FAQModel {
private String question, answer;
public String getQuestion() {
return question;
}
public String getAnswer() {
return answer;
}
}
Is it possible to create a table in the Room without a primary key?
Yes you can, with some difficulty, but not via room annotation, and even still it would have a primary key so really the answer is No.
It is possible (e.g. via a callback) to create a table that does not appear to have a primary key column e.g. CREATE TABLE IF NOT EXISTS the_table (question TEXT, answer TEXT). However,
it would have a primary key on the column rowid which is normally hidden.
such a table would not be able to be readily used, as you would have to avoid Room's compilation time SQL statement checking.
you could also not take direct advantage of Room's underlying table to/from object handling.
However, you make the comment
But in the android app I only get the question and answer column and I am not getting faqId because I don't want to use it inside my app.
So you could have a POJO class that excludes the faqId column e.g.
class FAQModelLessIdColumn {
String question,answer;
}
Assuming that FAQModel is the entity and thus the tablename then with the above you could have an #Query such as:-
#Query("SELECT * FROM faqmodel")
abstract List<FAQModelLessIdColumn> getFAQModelsLessTheFaqIdColumn();
However, over time, you will probably learn that the primary key column, is highly beneficial as it MUST uniquely identify a single row in the table. So from a single value you can perform CRUD operations efficiently.
As an analogy consider the table as a list where the questions have been written down in no particular order. To find a question and it's answer How many days in a leap year then you would have to search the entire list until you found the question. If however the list was split into lists according to the first character of the question and these were maintained in order then by skipping to the H list would likely make finding the question easier. Thus indexes can greatly reduce search times. So having the faqId available enables searches via the primary index and they will be faster.

How to model a relational database that stores order details?

I am making a restaurant POS app for android and I am trying to decide the best way to model the database for it using Room ORM that ensures maintainability. My database needs, among a lot of other things, to keep a record of all items sold within a transaction/order, as well as a log of the orders themselves and a list of the food products sold within the restaurant.
Considering the following tables (for brevity purposes I only include columns I think relevant to the question and may not illustrate all the information I will need to catalog), I can create a table that includes a log of all the orders ever placed and call it all_orders:
all_orders
-----------
id (PK)
oder_details_id (FK) - referencing the PK from order_details table
date
notes
total
payment_type
I can also create a table that contains all the food products/dishes that the restaurant serves, and we’ll call it all_items:
all_items
---------
id (PK)
name
category
price
No problems there so far, but my current confusion lies here—how do I manage to keep a log of the actual food items sold within an order?
One approach I thought about was to create a table per order number, but creating tables dynamically is already a problem and having 60,000 tables at the end of the year will be a maintainability nightmare.
So my other possible solution is to create a table called order_details that will probably end up with hundreds of thousands of entries per year with the following columns:
order_details
-------------
id (PK)
item_id (FK) - referencing the PK from the all_items table
order_id (FK) - referencing the PK from the all_orders table
quantity_ordered
And when a user wants to pull up an order from say, last week, the program can use a join query that will produce the following to be displayed in the app’s UI:
order
---------
id (PK)
date (from the all_orders table)
name (from all_items)
category (from all_items)
price (from all_items)
total (from all_orders)
payment_type (from all_orders)
I am afraid that the order_details table is just too broad since it will contain hundreds of thousands of entries, and querying it for entries will be sluggish. I'm sure indexing it will help, but is this the correct approach to this problem? If not, is there a better, “best practice” solution? If possible something that focuses on grouping any order and its items together without just dumping all items from all orders into one table. Any help will be most appreciated.
Edit: This question is not a duplicate of this, and while helpful, the supplied link has not provided any additional context on what I am really asking about nor is it entirely relevant to the answer I am after. I have bolded my last original paragraph since my question is really about a how I can model the above data as it isn't clear to me based on my research how to store actual order details attached to an order (many tutorials/similar questions I've come across fail short of thoroughly explaining the aforementioned).
The all_orders table would be superfluous as that is just repeating other data and would be contrary to normalisation.
You probably want a category table rather than repeat data (i.e. normalise categories).
Likewise, you also probably want a payment_type table (again to normalise).
Creating individual tables for orders would probably just create a nightmare.
Price and total aren't they the same? Saying that totals can be derived when extracting the data so there is no need to store such information.
As such the following structure schema may be close to what you want :-
DROP TABLE IF EXISTS item;
DROP TABLE IF EXISTS category;
CREATE TABLE IF NOT EXISTS category (_id INTEGER PRIMARY KEY, category_name TEXT);
CREATE TABLE IF NOT EXISTS item (
_id INTEGER PRIMARY KEY,
item_name TEXT UNIQUE,
category_ref INTEGER REFERENCES category(_id) ON DELETE CASCADE ON UPDATE CASCADE,
item_price REAL
);
DROP TABLE IF EXISTS payment_type;
CREATE TABLE IF NOT EXISTS payment_type (
_id INTEGER PRIMARY KEY,
payment_type TEXT UNIQUE,
surcharge REAL
);
-- NOTE cannot call a table order as it is a keyword (not rea true but have to enclose the name e.g.g [order]).
DROP TABLE IF EXISTS customer_order;
CREATE TABLE IF NOT EXISTS customer_order (
_id INTEGER PRIMARY KEY,
customer_name TEXT,
date TEXT DEFAULT CURRENT_TIMESTAMP,
payment_type_ref INTEGER REFERENCES payment_type(_id) ON DELETE CASCADE ON UPDATE CASCADE
);
DROP TABLE IF EXISTS order_detail;
CREATE TABLE IF NOT EXISTS order_detail (
customer_order_ref INTEGER REFERENCES customer_order(_id) ON DELETE CASCADE ON UPDATE CASCADE,
item_ref REFERENCES item(_id) ON DELETE CASCADE ON UPDATE CASCADE,
quantity
);
Example
The following is native SQL that demonstrates the schema above :-
Part 1 adding (inserting) the data :-
INSERT INTO category (category_name) VALUES
('Fish'),('Beef'),('Chicken'),('Lamb'),('Sea Food')
;
INSERT INTO item (item_name, item_price, category_ref) VALUES
('Fish and Chips',11.30,1),
('Steak and Kidney Pudding',15.45,2),
('Lamb Chops, Mashed Potato and Gravy',17.40,3)
;
INSERT INTO payment_type (payment_type, surcharge) VALUES
('Master Card',0.05),('Visa',0.05),('Cash',0),('American Express',0.15)
;
INSERT INTO customer_order (customer_name, payment_type_ref) VALUES
('Fred',3),
('Mary',1),
('Tom',2),
('Jane',4)
;
INSERT INTO order_detail (customer_order_ref, item_ref, quantity) VALUES
(1,1,2),(1,2,1), -- Fred (id 1) orders 2 Fish and Chips (id 1) and 1 Steak and Kidney (id 2)
(2,3,10), -- Mary orders 10 Lamb chops
(3,2,1),(3,1,1),(3,3,1), -- Tom orders 1 of each
(4,1,1) -- Just Fish and chips for Jane
;
Part 2 - Extracting Useful(perhaps) Data
Here's and example of what you can do with SQL which includes derived data (as suggested above) :-
SELECT
customer_name,
date,
group_concat(item_name) ||'('||quantity||')' AS items,
sum(item_price) AS total_price,
payment_type,
round(sum(item_price) * surcharge,2) AS surcharge,
round((sum(item_price) * surcharge) + sum(item_price),2) AS total_price
FROM customer_order
JOIN order_detail ON customer_order._id = order_detail.customer_order_ref
JOIN item ON order_detail.item_ref = item._id
JOIN payment_type ON customer_order.payment_type_ref = payment_type._id
GROUP BY customer_order._id -- Treats all data for an order as a single row allowing the use of aggregate functions on the groups e.g. sum, group_concat
;
Result

Designing date orientated database sqlite

I'm new in sqlite. I've built database but based on query I was trying to solve for it (which was over-complicated), I was suggested to look into normalising database, which I did, but can't seem to find examples on database that would be orientated around dates like a diary, with lots of daily entries. I'm working on app that would help log in everyday what I've eaten, what exercise did I do, what activities I've done, what was my well-being, how many hours I've slept. I will be able to go back to any day in the past and see what I was up to, so it will have to look up all entries for that particular date.
So I understand I need separate tables for food type, exercise type, activities types, event types and I need main table "diary" which will log each time date and id referencing another table. So I'm wondering if in that diary table I can have date column, id column and lets say type column (which will differentiate which table does id column references) or should I rather have date column and column for each of the other tables ids, even though I will be logging only one type at the time?
Also, would indexing the date column be a good idea?
Or maybe there is a better way to design that database? Any suggestions will be appreciated.
So I understand I need separate tables for food type, exercise type,
activities types, event types
If normalising then perhaps consider a single table for all types with a column to indicate the type.
So I'm wondering if in that diary table I can have date column, id
column and lets say type column (which will differentiate which table
does id column references) or should I rather have date column and
column for each of the other tables ids, even though I will be logging
only one type at the time?
If you are logging and assuming human input (as opposed to automated) then it is highly likely that a timestamp would be sufficient to uniquely identify a row.
As such there would be little need for an id column(in theory).
Saying that SQLite, unless you specify WITHOUT ROWID (which you might consider, this may be of use in deciding:-Clustered Indexes and the WITHOUT ROWID Optimization ), automatically creates a unique row identifier column i.e ROWID.
If you code a column as columnname INTEGER PRIMARY KEY or columnname INTEGER PRIMARY KEY AUTOINCREMENT then columnname becomes an alias for ROWID, in which case the unique value will be provided, if you do not provide a value when inserting.
However, if you were to specify timestamp INTEGER PRIMARY KEY and provide the current date/time as a value for the column when inserting, the current date/time would be stored and would also be indexed (it would have to be unique (current date/time would very likely be)).
So I'd suggest that a log entry need only be something like CREATE TABLE log (timestamp INTEGER PRIMARY KEY, eventref INTEGER);, where eventref is a reference to the event type.
As _id is required at times e.g. for a CursorAdapter then you could specify the columns to be extracted as *, timestemp as _id (3 columns timestamp, eventref and _id (timestamp and _id would be identical))or timstemp as _id, * (3 columns but _id, timestamp and eventref) or timestamp as _id, eventref (2 columns _id and eventref).
So using this model as the basis would minimise columns and be indexed automatically.
An example
You may have the events table as :-
Along with log table as :-
A query such as SELECT * FROM log JOIN events WHERE eventref = _id would give:-
Note! made up timestamps for illustration purposes

Database tool for Android other than SQLite?

I am new to Android programming and I have made a few simple apps which use SQLite to store user's data. Now I am working on a little more complex app in which I need to implement many-to-many relationship among the tables.
So basically, I have three layers (3 Tables) that would be connected to each other and I can't find a good tutorial or any documentation on how to do it. I've spent weeks on researching this. I also looked into realm-database but it's complicated for many-to-many table setup.
So is there any easier solution to this for a beginner? Or is there another tool that I can use to accomplish my task. Any suggestions would be helpful. Thank you :)
Your example isn't a many to many relationship. It's a one to many, each country can only exist in one continent and each state in only one country.
You can get the structure you want by adding a reference to the parent type's ID.
CREATE TABLE continent (
_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL
)
CREATE TABLE country (
_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
continentId INTEGER NOT NULL,
name TEXT NOT NULL,
FOREIGN KEY continentId REFERENCES continent(_id)
)
CREATE TABLE state (
_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
countryId INTEGER NOT NULL,
name TEXT NOT NULL,
FOREIGN KEY countryId REFERENCES country(_id)
)
To select all the countries on a continent, just ask SQL using the correct ID.
SELECT *
FROM country
WHERE continentId = ?
Or you can join them together.
SELECT *
FROM continent
JOIN country ON continent._id = country.continent
JOIN state ON country._id = state.countryId
You can do many-to-may relationships with SQLite. For the example shown you just need some XREF tables. For example (pseudocode):
Table CONTINENT(
ContinentID
,ContinentName
)
Table COUNTRY(
CountryID
,CountryName
)
Table CONTINENT_COUNTRY_XREF (
Continent_Country_XrefID
,ContinentID
,CountryID
)
Hope this helps.
Yes you can use Ultralite database from SAP. It supports joins as well.
More details here
http://scn.sap.com/community/developer-center/mobility-platform/blog/2012/08/23/how-to-open-an-ultralite-db-udb
To connect two tables in a many to many relationship, create a third table with three columns. The first column is just a standard is for the primary key. The other two columns are secondary keys into the two original tables. Googling " many to many relationship" will provide more details.

SQL: Cross table with foreign keys to two different tables

I have three tables:
zip_code_data
|zipCodeId| primary key
|zipCode| indexed
|other columns...|
location_data
|locationDataId| primary key
|city| indexed
|other columns...|
x_data
|id| primary key
|zipCodeId| foreign key
|locationDataId| foreign key
My goal is to run a query for either zipcode or city, and get all of the data associated with it from the zip_code_data and location_data tables
For example, if a user searches for a zipcode, I want to pull back all of the data associated with that zipcode from both tables.
My first guess is to get the foreign keys first from the cross table (x_data, example below) and then use those to get the data from each respective table... Since i'm somewhat of a novice user I don't know the best way to do this.
SELECT x_data.zipCodeId, x_data.locationDataId
FROM x_data
INNER JOIN zip_code_data
ON x_data.zipCodeId=zip_code_data.zipCodeId
WHERE zip_code_data.zipCode LIKE '2322%'
You could create an inline view:
select zips.othercolumn, LOCS.city
from zips
inner join x_data on zips.zip = x_data_zip and zips.zip like .....
left join (
select id, locations.city from locations
where locations.id = x_data.locationid
) as LOCS
or just join the locations table:
left join locations as locs on locs.locationid = x_data.locationid
I was about to post:
SELECT zip.*,loc.*
FROM x_data xref
JOIN zip_code_data zip ON zip.zipCodeId=xref.zipCodeID
JOIN location_Data loc ON loc.locationDataID=xRef.locationDataID
WHERE zip.zipCode LIKE '2322%' or loc.city LIKE '%aaa%'
but it looks like you've already got it...

Categories

Resources