SQLite: how to organize my data base - android

I am having a simple android app and want to know the best way to organize my database tables (mysql).
The idea of the app is a list of categories then the user presses on one of these categories and he gets another list of items and when he clicks on one of them, he gets details about it.
For example, the first list (countries) has (UK, US, China, Japan, and other countries)
You click on US, you get another list (states) has (California, NY, Arizona,...)
You click on California, you get its details (population, area, capital)
Same thing would happen if you click UK then London...
So, how should I arrange my data, should I make:
one table for countries and another table for each country,
only one big table for all states and it will have a column to say which country does it belong to.
any other suggestion?

Try something like the following.. and go from there..
create table countries (
id int(11) not null auto_increment,
name varchar(255) not null,
primary key (id)
);
create table states (
id int(11) not null auto_increment,
name varchar(255) not null,
country_id int(11) not null,
primary key (id)
constraint foreign key (country_id) references countries(id) on delete cascade
);
create table properties (
name varchar(255) not null,
primary key (name)
);
create table state_properties (
id int(11) not null auto_increment,
property varchar(255) not null,
state_id int(11) not null,
primary key(id),
constraint foreign key (property) references properties(property) on delete cascade,
constraint foreign key (state_id) references states(id) on delete cascade
);
edited: typo

You should make the 3 table 1 for countries and another for states and another for details.
Reason:
By this there will not be redundant data and it follows the normalization rules.
you will get the only data which you want not other than that.
You can use the form submit or ajax to get the data from the tables.
EDITED:
As per asked by IAM the data in the database as you will store the data of details corresponding of states and then states corresponding of countries then there you will enter the countries name multiple times in a single column for each states. Then such the data of countries and states will be multiple time in database and your database will be heavy.

Assuming that the information is stored as JSON or XML blobs, you should have TWO tables. Not one or three. Build from the ground up.
CREATE TABLE locale (locID int PRIMARY KEY, data BLOB )
CREATE TABLE localGrouping (
groupID int PRIMARY KEY,
groupName varchar(255),
parentGroup int NULL,
locID int NULL
)
You mentioned that want to have a list of countries, and then drill down to cities or states. Which is all find and dandy, but what happens if you want to include stats at the state level above the city? Or the city level above the neighborhood?
A proper database normalization, as in any proper programming, follows the "Zero One Infinity" rule. Especially when it comes to hierarchical data sets.
(Of course, feel free to add however many tables are apporopriate from LOCALE on down. But unless you're going to be running comparative indexes on a locale's properties, a serialized data object should be fine.)

Related

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

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.

INSERT OR REPLACE for sqlite rows with dependent foreign tables

Say I have table Book and table Page. Say that table Page has book's dbId as a foreign key. When I do an INSERT OR REPLACE on a Book row, does that change the dbId of the book?
Say the book is title="Song of Songs", author="King Solomon",pages=50" say that I want to change the title of the book and that will lead to replacement of the row. So the question is: will the replace cause the dbId of the book to change? I imagine it shouldn't, but I just don't know.
So this is about ON CONFLICT REPLACE
The documentation says about INSERT OR REPLACE:
When a UNIQUE or PRIMARY KEY constraint violation occurs, the REPLACE algorithm deletes pre-existing rows that are causing the constraint violation prior to inserting the current row and the command continues executing normally.
If the new dbId has the same value as the old one, it does not change (obviously). But if the constraint violation happens in another column, the new dbId might have a different value (especially if it's an autoincrementing column).
For implementing your idea :
1:) First get to foreign key from the first table using select query.
2:) then create a function with a parameter through which you can pass this foreign key in process of getting relevant data using the foreign key from the foreign table.
3:) Now use below query for fetching to related data using that key-
databaseObject.update(TABLE_NAME, values, COLOMN_NAME + " = ?",
Array_of_replacing_values);

Dynamic Tables in Android SQLite

My question involves databases - The scenario is this:
I have an app that tracks when people borrow items. I have an existing table which tracks who they are, what they have borrowed and so on. What I would like to do is create a separate table to track what the person has borrowed, their contact info, if they returned it, etc.
My idea to do this would be to create a Dynamic table in SQL that would hold the records for 1 person, ie
John Smith
DVD; July 12, 2012; Returned in good condition; etc
As I'm still learning, I wanted to know if:
This is possible, feasible or if there is a smarter way of going about it.
Your answer depends on your scenario;
If you are only interested with "who" borrowed "what" (currently) and not "when" except last occurance, and you are assuming there are always only 1 copy of an item, then you can use one to one relation as:
CREATE TABLE Person
(
PersonId int IDENTITY(1,1) NOT NULL,
Name nvarchar(30) NOT NULL,
Surname nvarchar(30) NOT NULL,
BorrowItemId int NULL FOREIGN KEY REFERENCES Item UNIQUE,
BorrowDate datetime NULL,
ReturnDate datetime NULL,
ReturnCondition nvarchar(50) NULL,
CONSTRAINT PK_Person PRIMARY KEY CLUSTERED (PersonId ASC),
)
CREATE TABLE Item
(
ItemId int IDENTITY(1,1) NOT NULL,
ItemDescription nvarchar(50) NOT NULL,
CONSTRAINT [PK_Item] PRIMARY KEY CLUSTERED (ItemId ASC)
)
If you have multiple copies of each item you should remove the UNIQUE key on BorrowItemId changing relation to one to many. In case;
To see the items borrowed and returned with person information:
SELECT PersonId, Name, Surname, ItemDescription, ReturnDate, ReturnCondition
FROM Person INNER JOIN Item
ON BorrowItemId = ItemId
WHERE BorrowItemId IS NOT NULL
AND ReturnDate IS NOT NULL
You can add PersonId filter in WHERE clause to query for specific person
This isn't a good design since you can insert records without date information or you can even have records with date info but no related BorrowItemId. I suggest using many to many and keep historic data (can be handy) or overwrite using update each time the person borrows a new item
Their contact information could be linked into the table which tracks who they are.
If you have not created a table yet for the returns then I suggest you reference the borrowing table's ID and set in the borrowing table a flag to say this item has been returned.
I am not too sure why you would want to create a new table to collate all the information. If you want to get all the information together then I suggest using the SQL keywrod JOIN when preparing statements. If you really want to store the information later on in a table you can but it will just be duplicates in your database.
A tutorial on the different types of joins you can do : http://www.w3schools.com/sql/sql_join.asp
It is definitely possible to do as you describe. It really isn't a very good strategy, though. Your new table is, exactly, equivalent to an additional column in the existing table that tags the row as belonging to a specific individual.

Automatically Create Insert Statements to Fill Junction Table in a Pre-Created DB

For a simple android app I'm creating as a teaching tool for myself (for using relational dbs/SQL among other things - pardon the simplicity of the question if you will). I'm pre-creating a sqlite db to ship with the application. I'm doing this based on the following SO question.
I've got two tables with a many to many relationship and a junction table to define those relationships as follows:
CREATE TABLE Names (_id INTEGER PRIMARY KEY,
name TEXT
);
CREATE TABLE Categories (_id INTEGER PRIMARY KEY,
category TEXT
);
CREATE TABLE Name_Category (name_id INTEGER,
category_id INTEGER,
PRIMARY KEY (name_id, category_id),
foreign key (name_id) references Names(_id),
foreign key (category_id) references Categories(_id)
);
I've got sets of insert statements to fill the Names and Categories tables. I'm now faced with the task of filling the junction table. I'm sure that I could create the insert statements by hand by looking up the ids of the names and categories that I want to match, but that seems a bit silly.
In order to automatically create the insert statements for the junction table, I imagine that I could create a script based on a set of name and category pairs that will search for the appropriate ids and dump an insert statement. (I came up with this as I was asking the question and will research it. Don't you love it when that happens?)
Does anybody have any suggestions for ways to do this?
EDIT I added the foreign keys because, as pointed out below, they'll help maintain integrity between the tables.
EDIT #2 To solve this, I created a simple Perl script that would take a text file with name - category pairs and dump them out into another file with the appropriate SQL statements.
The name - category text file has a format as follows:
'Name' 'Category'
The Perl script looks like this:
use strict;
use warnings;
open (my $name_category_pair_file, "<", "name_category.txt") or die "Can't open name_category.txt: $!";
open (my $output_sql_file, ">", "load_name_category_junction_table.sqlite") or die "Can't open load_name_category_junction_table.sqlite: $!";
while (<$name_category_pair_file>) {
if (/('[a-zA-Z ]*') ('[a-zA-Z ]*')/) {
my $sql_statement = "INSERT INTO Name_Category VALUES (
(SELECT _id FROM Names WHERE name = $1),
(SELECT _id FROM Categories WHERE category = $2))\;\n\n";
print $output_sql_file $sql_statement;
}
}
close $name_category_pair_file or die "$name_category_pair_file: $!";
close $output_sql_file or die "$output_sql_file: $!";
You can use this insert in your script or code (replacing the strings or using ?):
insert into Name_Category values(
(select _id from Categories where category='CAT1'),
(select _id from Names where name='NAME1'));
Also, you can alter the Name_Category table to constraint on the values that can be inserted and/or deleted:
CREATE TABLE Name_Category ( name_id INTEGER NOT NULL,
category_id INTEGER NOT NULL,
PRIMARY KEY (name_id, category_id),
foreign key (name_id) references Names(_id),
foreign key (category_id) references Categories(_id));
create two main tables first and then create a junction table in which primary key of both main tables will be available as foreign key.. Primary key of junction table will be union
of primary key of first and second main table.
Create trigger now to automatically insert into junction table...
Also don't forget to create table with cascade deletion and cascade updatation so that any value updated or deleted in main tables will be automatically reflected in junction table

Categories

Resources