Access all rows in table that is linked to another table - sqlite

I have 2 tables in SQLite. One is called contacts and the other is phoneNumbers. phoneNumbers is linked to contacts with integer references. Here is the tables:
CREATE TABLE contacts(
id INTEGER PRIMARY KEY,
name text
);
CREATE TABLE phoneNumbers(
id INTEGER PRIMARY KEY,
homePhone text,
contact_id INTEGER REFERENCES contacts(id)
);
My question is, how can I access all homePhone that is linked to contacts (id) 1?
Hope this is clear. If you have any questions, feel free to ask in the comments.

Here you have it:
SELECT homePhone
FROM phoneNumbers
JOIN contacts
ON homePhone.contact_id=contacts.id
WHERE contacts.id=1
And never use SELECT * :
https://stackoverflow.com/a/3639964/1919749

Related

Insert primary key of unique value into foreign key

If I have a two tables like this:
CREATE TABLE users
(
id INTEGER PRIMARY KEY,
username TEXT UNIQUE NOT NULL
);
CREATE TABLE games
(
id INTEGER PRIMARY KEY,
player1 INTEGER REFERENCES users,
player2 INTEGER REFERENCES users,
comment TEXT
);
How can I insert a new row into the games table given two usernames?
The primary keys of the users would need to be looked up by their names in the users table first and then inserted into the games table. What's the best way to do this?
So, instead of
INSERT INTO games (player1, player2)
VALUES (1, 2);
how can I combine this with looking up the id values from usernames?
You could use subqueries to lookup the two usernames based on their ids:
INSERT INTO games (player1, player2, comment)
SELECT
(SELECT username FROM users WHERE id = 1),
(SELECT username FROM users WHERE id = 2),
'good luck';

Except the name of table what property can use to differentiate these tables

I have a database which contains many tables and these tables can be added or removedd any time.So I give each of them a different name like Table1,Table2,...
but it's uncomfortable to use these table because sometime I forget what infomation was stored in Table1
So I want something to differentiate these all tables, some property that I can be specified when I create a table and I can use to access a specific table when I need to fetch informations from that table
As one comment says, you could create a table for notes on the other tables:
CREATE TABLE notes (
id INT AUTO_INCREMENT,
table_name VARCHAR(64),
note VARCHAR(255),
PRIMARY KEY (id)
);
By the way, MySQL (but not SQLite) allows comments on the table itself:
CREATE TABLE table1 (
id INT AUTO_INCREMENT,
val INT,
PRIMARY KEY (id)
) COMMENT = 'Table of stuff';
-- Show the comment
SHOW TABLE STATUS WHERE NAME='table1';
-- Just show names and comments
SELECT `TABLE_NAME`, `TABLE_COMMENT`
FROM information_schema.tables
WHERE table_schema = DATABASE();

Complex query on sql lite xcode

I'm developing an iOS app and I have a sqlite database with 2 tables related by 1-to-many relationship.
Now I would like to do a query that retrieve all element by first table and in the same time do a count by second table so I can pass the result into my view.
CREATE TABLE track(
trackid INTEGER,
trackname TEXT,
trackartist INTEGER,
FOREIGN KEY(trackartist) REFERENCES artist(artistid)
);
CREATE TABLE artist(
artistid INTEGER PRIMARY KEY,
artistname TEXT
);
I would like to create a query that returns all artist name and the count of track for each artist name so I can pass this value to my list.
Is it possible? Any help?
Thanks to Joe, your code works well for my, but it's possibile to add new field for store the result of count?
Sorry and if i would take the also all trackname for each artist in the same query?
SELECT a.artistname, count(*)
FROM track t
INNER JOIN artist a
on t.trackartist = a.artistid
GROUP BY a.artistid
Try this:
SELECT a.artistname,
(SELECT COUNT(*) FROM track t
WHERE t.trackartist = a.artistid)
FROM artist a

Make own like system for various content

There are three types of content in my database. They are Songs, Albums and Playlists. Albums and Playlists are just collections of songs. And I want to let the user put like for each of them. I made table with columns
LikeId UserId SongId PlaylistId AlbumId
for storing likes. For example if user puts like to song, I put song's id into SongId column and user's id into UserId column. Other columns will be null. It's working good,but I don't like this solution because it's not normalized.
So I want to ask if there are better solutions for this.
You should just create 3 tables - one for User paired with each of Playlist, Song, and Album. They'd look something like:
CREATE TABLE PlaylistLikes
(
UserID INT NOT NULL,
PlaylistID INT NOT NULL,
PRIMARY KEY (UserID, PlaylistID),
FOREIGN KEY (UserID) REFERENCES Users (UserID),
FOREIGN KEY (PlaylistID) REFERENCES Playlists (PlaylistID)
);
CREATE TABLE SongLikes
(
UserID INT NOT NULL,
SongID INT NOT NULL,
PRIMARY KEY (UserID, SongID),
FOREIGN KEY (UserID) REFERENCES Users (UserID),
FOREIGN KEY (SongID) REFERENCES Songs (SongID)
);
CREATE TABLE AlbumLikes
(
UserID INT NOT NULL,
AlbumID INT NOT NULL,
PRIMARY KEY (UserID, AlbumID),
FOREIGN KEY (UserID) REFERENCES Users (UserID),
FOREIGN KEY (AlbumID) REFERENCES Albums (AlbumID)
);
Here, having both columns in the primary key prevents the user from liking the song/playlist/album more than once (unless you want that to be available - then remove it or maybe keep track of that in a 'number of likes' column).
You should avoid putting all 3 different types of likes in the same table - different tables should be used to represent different things. You want to avoid "One True Lookup Table" - here's one answer detailing why: OTLT
If you want to query against all 3 tables, you can create a view which is the result of a UNION between the 3 tables.
How about
LikeId UserId LikeType TargetId
Where LikeType can be "Song", "Playlist" or "Album" ?
Your solution is fine. It has the nice feature that you can set up explicit foreign key relationships to the other tables. In addition, you can verify that exactly one of the values is set by adding a check constraint:
check ((case when SongId is null then 0 else 1 end) +
(case when AlbumId is null then 0 else 1 end) +
(case when PlayListId is null then 0 else 1 end)
) = 1
There is an overhead incurred, of storing NULL values for all three. This is fairly minimal for three values.
You can even add a computed column to get which value is stored:
WhichId = (case when SongId is not null then 'Song'
when AlbumId is not null then 'Album'
when PlayListId is not null then 'PlayList
end);
As a glutton for punishment, I would use three tables: UserLikesSongs, UserLikesPlaylists and UserLikesAlbums. Each contains a UserId and an appropriate reference to one of the other tables: Songs, Albums or Playlists.
This also allows adding additional type-specific information. Perhaps Albums will support a favorite track in the future.
You can always use UNION to combine data from the various entity types.

SQLite Multi-column Insert/Replace with Multiple Join

Sorry for the poor title. I have a query (below) that executes properly and creates an insertion just as I would desire. However, I want to make it smarter by only inserting when the exact combination of three columns. Essentially, the three column tuple is a primary key, but I'm working with the limitation of sqlite's single primary key.
Basic Context
I have 4 tables: Permissions, Roles, Users, Actions
Permissions connects Roles and Users to Actions. The Actions table has a list of available tasks that a User or a user with a Role can perform. So for example, if user_id = 1 can perform a list_folder action (action_id = 1), then the permissions table would have an entry: (id=1, action_id=1, user_id=1, role_id=NULL). Likewise, suppose an owner_role (role_id=1) might have permissions to perform a list_folder action (action_id=1), then the permissions entry might be: (id=2, action_id=1, user_id=NULL, role_id=1).
When I do an insert, I want to make sure that I do not already have that exact combination (e.g. action_id=1, user_id=NULL, role_id=1). And I'm not entirely sure how to write the sql so that I have this setup properly.
Here's my basic insert statement. I need to come up with an insert and a replace statement:
INSERT INTO permissions (
action_id
,role_id
)
SELECT DISTINCT
a.id as "action_id"
,r.id as "role_id"
FROM tmp_permissions tmp
LEFT OUTER JOIN actions a
ON tmp.action_name = a.name
LEFT OUTER JOIN roles r
ON tmp.roles_name = r.name
LEFT OUTER JOIN permissions p
ON p.role_id
Here are some creation sql statements for the tables:
CREATE TABLE permissions (
id INTEGER NOT NULL,
enabled INTEGER,
action_id INTEGER,
user_id INTEGER,
role_id INTEGER,
PRIMARY KEY (id),
FOREIGN KEY(user_id) REFERENCES users (id),
FOREIGN KEY(action_id) REFERENCES actions (id),
FOREIGN KEY(role_id) REFERENCES roles (id)
);
CREATE TABLE actions (
id INTEGER NOT NULL,
enabled INTEGER,
name VARCHAR(50),
permission_ids INTEGER,
PRIMARY KEY (id),
FOREIGN KEY(permission_ids) REFERENCES permissions (id)
);
CREATE TABLE roles (
id INTEGER NOT NULL,
enabled INTEGER,
name VARCHAR(50),
permission_ids INTEGER,
PRIMARY KEY (id),
FOREIGN KEY(permission_ids) REFERENCES permissions (id)
);
CREATE TABLE users (
id INTEGER NOT NULL,
enabled INTEGER,
name VARCHAR(50),
permission_ids INTEGER,
PRIMARY KEY (id),
FOREIGN KEY(permission_ids) REFERENCES permissions (id)
);
Here's a temp table I'm using to store the data in the table while I work with it:
CREATE TABLE tmp_permissions(
roles_name VARCHAR(50),
action_name VARCHAR(50)
);
Here's some data:
#role|action
admin|setup
admin|debug
admin|login
admin|view_user
manager|view_employee
manager|enroll_employee
manager|login
employee|schedule
employee|login
customer|guest_login
customer|change_credentials
guest|guest_login
Thanks in advance!
Add a UNIQUE constraint to the table:
CREATE TABLE permissions(
... ,
UNIQUE (action_id, user_id, role_id)
)
You can then use any of the conflict resolution algorithms to handle duplicates.

Resources