Create views for user profile management - sql

I have the below schema for user profile management,
CREATE TABLE IF NOT EXISTS users
(
userid TEXT NOT NULL,
name TEXT NULL,
lmessage INTEGER NULL,
statusid INTEGER NULL,
/* statusid should refer to last status of the user in status table*/
locationid INTEGER NULL,
/* locationid should refer to last status of the user in locations table */
registered INTEGER NOT NULL,
tinypic INTEGER NULL
/* this refers to media id in media table */,
largepic INTEGER NULL
/* this also refers to media id in media table */,
groupid INTEGER NULL
/* this refers to id in groups table */ ,
PRIMARY KEY (userid)
);
CREATE TABLE IF NOT EXISTS locations
(
serial INTEGER,
locationid TEXT NOT NULL,
userid TEXT NOT NULL,
time INTEGER NULL,
PRIMARY KEY (serial)
);
CREATE TABLE IF NOT EXISTS status
(
serial INTEGER,
userid TEXT NULL,
message TEXT NOT NULL,
time INTEGER NULL,
PRIMARY KEY (serial)
);
CREATE TABLE IF NOT EXISTS messages
(
sno INTEGER,
messageid INTEGER NOT NULL,
sender TEXT NOT NULL,
receiver TEXT NOT NULL,
time INTEGER NULL,
message TEXT NULL,
image INTEGER NULL,
video INTEGER NULL,
audio INTEGER NULL,
PRIMARY KEY (sno)
);
CREATE TABLE IF NOT EXISTS media
(
mediaid TEXT NOT NULL UNIQUE,
url TEXT NULL,
downloaded INTEGER NULL,
thumbnail TEXT NULL,
PRIMARY KEY (mediaid)
);
CREATE TABLE IF NOT EXISTS groups
(
serial INTEGER,
name TEXT NOT NULL,
id INTEGER NOT NULL
PRIMARY KEY(serial)
);
CREATE UNIQUE INDEX IF NOT EXISTS id_unique ON users (userid ASC);
CREATE UNIQUE INDEX IF NOT EXISTS serial_unique ON status (serial ASC);
CREATE UNIQUE INDEX IF NOT EXISTS id_unique ON messages (sno ASC);
CREATE UNIQUE INDEX IF NOT EXISTS serial_unique ON patterns (serial DESC);
CREATE UNIQUE INDEX IF NOT EXISTS mediaid_unique ON media (mediaid ASC);
How can create views on user table to get list of users based on filter conditions. Please suggest me schema design is not good.
A view example that I would like to add on this schema :
Select all users who belong to group and all groups created after that group.
Select all users with last message, status, location and media urls included.
Thanks.
Please Note that I am SQL nube, please forgive me if you feel like this is immature question. All I need is, I want to learn from reviews of other people.

for 1 - you need to have timestamp (INTEGER id you go by UTC ticks) in group table - it is missing
for 2 - you can do it with join
bot case i don't think you need to have a view unless you have some specific reasons. You can go by select queries with join to get required data.
I recommend you to use http://www.sqliteexpert.com/download.html - try out creating the schema there and try out all your queries before you get in to implementing it in android

Related

Adding an Array of INT column where each value is a primary key from another table

Given two tables like so
CREATE TABLE participants(
id SERIAL PRIMARY KEY,
Name TEXT NOT NULL,
Title TEXT NOT NULL
);
CREATE TABLE meetings (
id SERIAL PRIMARY KEY,
Organizer TEXT NOT NULL,
StartTime DATE NOT NULL,
EndTime DATE NOT NULL,
Participants INT[],
);
I want Participants column of 'meetings' table to contain set of integers which are all primary keys (specific participant) from 'participants' table.
How do I define this field in 'meetings' table ?
The old fashioned way is to create a many-many table, with a couple of commonsense constraints:
CREATE TABLE meetings_participants(
meeting_id int not null,
participant_id int not null,
primary key (meeting_id, participant_id),
foreign key(meeting_id) references meetings(id),
foreign key(participant_id) references participants(id)
)
Now it is easy to add and remove people to meetings be inserting or deleting rows or query meetings that e.g. have 4 or more participants.
A more common approach is to create a junction table for the meeting participants.
CREATE TABLE participants (
participant_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
Name TEXT NOT NULL,
Title TEXT NOT NULL
);
CREATE TABLE meetings (
meeting_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
Organizer TEXT NOT NULL,
StartTime DATE NOT NULL,
EndTime DATE NOT NULL
);
CREATE TABLE meeting_participants(
meeting_id INT NOT NULL,
participant_id INT NOT NULL,
PRIMARY KEY (meeting_id, participant_id),
FOREIGN KEY (meeting_id) REFERENCES meetings(meeting_id),
FOREIGN KEY (participant_id) REFERENCES participants(participant_id)
);
Which is then used to join the 2 tables.
For example:
SELECT m.*, p.*
FROM meeting_participants mp
JOIN meetings m USING(meeting_id)
JOIN participants p USING(participant_id)
WHERE m.Organizer = 'John Doe';

How to design a friend list in sql /sqlite

Im relatively new to sql and Im trying to create a relationship between two users.
A friend request has to be sent and accepted to be friends with each other. Now I have a third table called items. A user should now be able to see all items that are owned by his friends. Im kinda stuck writing this query...
item table:
CREATE TABLE IF NOT EXISTS item(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
owner VARCHAR(50) NOT NULL,
borrowedBy VARCHAR(50),
imageUrl TEXT
);
friendship table:
CREATE TABLE IF NOT EXISTS friendship(
friendship_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
);
user_friendship
CREATE TABLE IF NOT EXISTS user_friendship(
username VARCHAR(50) NOT NULL,
friendship_id INTEGER NOT NULL,
status INTEGER NOT NULL,
PRIMARY KEY (username, friendship_id)
);
You need to look at tutorials on how to build a SQL database, mainly on table relationship.
Here, for example, you don't need separate friendship and user_friendship table.
You could have one friendship table:
CREATE TABLE IF NOT EXISTS friendship(
friendship_id INTEGER NOT NULL,
username1 VARCHAR(50) NOT NULL,
username2 VARCHAR(50) NOT NULL,
status INTEGER NOT NULL,
PRIMARY KEY (friendship_id, username1 , username2 )
);
Note that you should use integer value for foreign keys, not varchar(50).

How should I structure my simple database?

I am creating a database (for data from an online game) in which I need to store Players and their Villages. Each Player has at least 1 village. All Villages are unique and every Village has exactly 1 owner(Player).
It is probably important to mention, that I intend to create a new table/tables every day since the online game in question releases an updated game world data file once every 24hours. Once a table is created, I will never have to make changes in it, I will only need to read data from it.
I came up with 2 solutions for now, but I dont know what the right approach is.
Solution1:
CREATE TYPE village_t AS (
id INTEGER,
x INTEGER,
y INTEGER,
village_id INTEGER,
village_name VARCHAR,
pop INTEGER,
region VARCHAR
);
CREATE TABLE players (
tribe INTEGER NOT NULL,
user_id INTEGER PRIMARY KEY,
user_name VARCHAR(30) UNIQUE NOT NULL,
aliance_id INTEGER NOT NULL,
aliance_name VARCHAR(30) NOT NULL,
villages village_t[]
);
Solution2:
CREATE TABLE players (
tribe INTEGER NOT NULL,
user_id INTEGER PRIMARY KEY,
user_name VARCHAR(30) UNIQUE NOT NULL,
aliance_id INTEGER NOT NULL,
aliance_name VARCHAR(30) NOT NULL
);
CREATE TABLE villages (
id INTEGER NOT NULL,
x INTEGER NOT NULL,
y INTEGER NOT NULL,
village_id INTEGER NOT NULL,
village_name VARCHAR NOT NULL,
user_id INTEGER,
CONSTRAINT fk_con FOREIGN KEY(user_id) REFERENCES players(user_id),
pop INTEGER NOT NULL,
region VARCHAR
);
CREATE INDEX idx ON villages(user_id);
You have a 1-n relationship. Each village ("n") has one owner ("1"). Your second solution is the canonical way of storing this information in a database.
Your first solution does not even enforce the notion that a village as one owner, so I'm not sure why you are considering it. The second imposes this condition as part of the data model.
Your second solution has set up the recommend foreign key and indexes for what you describe, by the way, so it looks fine.
If you need to read village data frequently, Solution 1 is not recommended. This is because the list of village ids design removes the scope of joining the person and village table
Solution 2 is the most preferred way of going about as it keeps all your options open (whether you would frequently need village data or not)
Another way of going about solution 2 is to create a cross-reference table for user_id and village_id
CREATE TABLE players (
tribe INTEGER NOT NULL,
user_id INTEGER PRIMARY KEY,
user_name VARCHAR(30) UNIQUE NOT NULL,
aliance_id INTEGER NOT NULL,
aliance_name VARCHAR(30) NOT NULL
);
CREATE TABLE villages (
id INTEGER NOT NULL,
x INTEGER NOT NULL,
y INTEGER NOT NULL,
village_id INTEGER NOT NULL,
village_name VARCHAR NOT NULL,
pop INTEGER NOT NULL,
region VARCHAR
);
CREATE TABLE xref_players_villages (
user_id INTEGER,
CONSTRAINT fk_con1 FOREIGN KEY(user_id) REFERENCES players(user_id),
village_id INTEGER,
CONSTRAINT fk_con2 FOREIGN KEY(village_id ) REFERENCES villages(village_id ),
);

Paginated conversations fetching with latest message

I am trying to create a simple chat application database schema, and query the conversations. My current table setup is the following:
CREATE TABLE chat_user (
id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
display_name VARCHAR(140),
... other user stuff ...
);
CREATE TABLE conversation (
id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
title VARCHAR(140),
created timestamp with time zone NOT NULL
);
CREATE TABLE conversation_message (
id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
conversation_id bigint NOT NULL,
sender_id bigint NOT NULL,
body TEXT NOT NULL,
created timestamp with time zone NOT NULL
);
CREATE TABLE conversation_participant (
id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
conversation_id bigint NOT NULL,
user_id bigint NOT NULL
);
So basically each conversation has its own title, and multiple participants. What I would like to do is fetch the conversations paginated, with N conversations on each page (where a certain user is a participant) sorted by the conversation creation date (or if possible by the date of the latest message). The result set should contain the id, title of the conversation and list of participants (id and display name) + the id, sender_id and body of the latest message in the conversation.
What would be the most efficient query to achieve this? Is there maybe some better way to model the schema with the described end goal in mind?

Postgresql multiple tables with same foreign key unique constraint

I have following tables on PostgreSQL 9.4
CREATE TABLE "user" (
id SERIAL PRIMARY KEY,
email CHARACTER VARYING NOT NULL,
password CHARACTER VARYING NOT NULL
);
CREATE TABLE "dealer" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES "user" (id) ON DELETE RESTRICT
);
CREATE TABLE "affiliate" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES "user" (id) ON DELETE RESTRICT
);
Is it possible to force user_id value to be unique across tables dealer and affiliate?
There are different setups to use for inheritance in SQL and for this you could just use an integer column type in the table user that marks the type of the user and would reference to table user_type (id,name) that would have the values 1,dealer and 2,affiliate:
CREATE TABLE user_type (
id INTEGER PRIMARY KEY, --could be SERIAL
name text
);
INSERT INTO user_type VALUES (1,'dealer'), (2, 'affiliate');
CREATE TABLE "user" (
id SERIAL PRIMARY KEY,
email CHARACTER VARYING NOT NULL,
password CHARACTER VARYING NOT NULL,
user_type INTEGER REFERENCES user_type NOT NULL,
UNIQUE(id,user_type)
);
This in itself wouldn't force uniqueness across tables so after implementing this you would have the following options:
Drop the tables dealer and affiliate - you won't need them if you rely on the type field to see which one the user is.
If you have to keep those inherited tables you can:
Use triggers - these triggers check the uniqueness and would be actived on INSERT or UPDATE
Another (a bit clumsy) solution: add user_type field to both subtables like this:
CREATE TABLE "dealer" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
user_type INTEGER NOT NULL DEFAULT 1 check (user_type = 1),
FOREIGN KEY (user_id,user_type) REFERENCES "user"(id,user_type) ON DELETE RESTRICT
);
CREATE TABLE "affiliate" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
user_type INTEGER NOT NULL DEFAULT 2 check (user_type = 2),
FOREIGN KEY (user_id,user_type) REFERENCES "user"(id,user_type) ON DELETE RESTRICT
);
The checks and foreign keys together make sure you cannot have both types of user in the main table. Note that user_id might be used as the PRIMARY KEY in the subtables too. Currently a row in user might have several dealer rows linked to it so at least you might want to set user_id foreign keys in subtables as UNIQUE.