Book,Author,Book_Author
(1) By anonymous on 2022-03-03 10:31:12 [link] [source]
i got this... create table book ( id int not null auto_increment, name text, primary key (id) ) create table author ( id int not null auto_increment, name text, primary key (id) ) create table book_author ( id int not null auto_increment, book_id int, author_id int, primary key (id) ) insert into book(name) values ('Science'), ('Math'), ('History'), ('Filipino'), ('English'); insert into author(name) values ('Harry Potter'), ('Ron Weasley'), ('Hermione Granger'), insert into book_author(book_id,author_id) values (1,1), (2,2), (2,3), (3,3), (4,3), (5,1), (5,3); i want the result: Science|Harry Potter Math|Ron Weasley,Hermione Granger History|Hermione Granger Filipino|Hermione Granger English|Harry Potter,Hermione Granger please teach me how...
(2) By Ryan Smith (cuz) on 2022-03-03 12:30:40 in reply to 1 [link] [source]
Firstly needed to fix some create table elements, then added some queries that demonstrate the steps in the process, each adding an important bit to get closer to the result.
-- SQLite version 3.37.2 [ Release: 2022-01-06 ] on SQLitespeed version 2.1.3.11.
-- ================================================================================================
create table book (
id INTEGER PRIMARY KEY,
name text
);
create table author (
id INTEGER PRIMARY KEY,
name text
);
create table book_author (
id INTEGER PRIMARY KEY,
book_id int,
author_id int,
UNIQUE(book_id,author_id)
);
insert into book(name) values
('Science'),
('Math'),
('History'),
('Filipino'),
('English');
insert into author(name) values
('Harry Potter'),
('Ron Weasley'),
('Hermione Granger');
insert into book_author(book_id,author_id) values
(1,1),
(2,2),
(2,3),
(3,3),
(4,3),
(5,1),
(5,3);
SELECT B.name AS Book, A.name AS Author
FROM book_author AS L
JOIN book AS B ON B.id = L.book_id
JOIN author AS A on A.id = L.author_id
;
-- Book |Author
-- ----------|------------------
-- Science |Harry Potter
-- Math |Ron Weasley
-- Math |Hermione Granger
-- History |Hermione Granger
-- Filipino |Hermione Granger
-- English |Harry Potter
-- English |Hermione Granger
SELECT B.name AS Book, group_concat(A.name) AS Authors
FROM book_author AS L
JOIN book AS B ON B.id = L.book_id
JOIN author AS A on A.id = L.author_id
GROUP BY Book
;
-- Book |Authors
-- ----------|-------------------------------
-- English |Harry Potter,Hermione Granger
-- Filipino |Hermione Granger
-- History |Hermione Granger
-- Math |Ron Weasley,Hermione Granger
-- Science |Harry Potter
SELECT B.name AS Book, group_concat(A.name) AS Authors
FROM book_author AS L
JOIN book AS B ON B.id = L.book_id
JOIN author AS A on A.id = L.author_id
GROUP BY Book
ORDER BY Book DESC
;
-- Book |Authors
-- ----------|-------------------------------
-- Science |Harry Potter
-- Math |Ron Weasley,Hermione Granger
-- History |Hermione Granger
-- Filipino |Hermione Granger
-- English |Harry Potter,Hermione Granger
(5.1) By Keith Medcalf (kmedcalf) on 2022-03-03 21:40:20 edited from 5.0 in reply to 2 [source]
I would have added not null collate nocase unique
to the definition of author.name
and book.name
because these are obviously unique identifiers of the tuple in the table and there is no other candidate key (though there is a psuedo-key created using the row-number -- this is a "short cut pseudo-key" for the actual tuple candidate key). If there were other candidate keys in the tables (such as an ISBN number for the book tuple) then this might change.
Also, I would name the id
elements of the book and author tuples so they match the usage of the name (same things are named the same) as book.book_id
and author.author_id
-- that is, every reference to the book-id pseudo-key is named book-id, no matter what table it is in. This is personal preference (it also allows the use of NATURAL JOIN
if one wished).
Also, there is no need for book_author
to be a rowid table -- the rowid is useless (as is organizing the table by rowid). All that is required is linkage from book_id to author_id and from author_id to book_id. Nothing is required beyond the b-tree indexes so there is no point in using a rowid table at all, and using the declaration shown here will result in no extraneous useless overhead of maintianing a rowid table.
create table book
(
book_id INTEGER PRIMARY KEY,
name text not null collate nocase unique
);
create table author
(
author_id INTEGER PRIMARY KEY,
name text not null collate nocase unique
);
create table book_author
(
book_id integer not null references book (book_id),
author_id integer not null references author (author_id),
primary key (book_id, author_id),
unique (author_id, book_id)
) WITHOUT ROWID;
insert into book(name) values
('Science'),
('Math'),
('History'),
('Filipino'),
('English');
insert into author(name) values
('Harry Potter'),
('Ron Weasley'),
('Hermione Granger');
insert into book_author(book_id,author_id) values
(1,1),
(2,2),
(2,3),
(3,3),
(4,3),
(5,1),
(5,3);
SELECT B.name AS Book, A.name AS Author
FROM book_author AS L
JOIN book AS B ON B.book_id = L.book_id
JOIN author AS A on A.author_id = L.author_id
;
SELECT B.name AS Book, group_concat(A.name) AS Authors
FROM book_author AS L
JOIN book AS B ON B.book_id = L.book_id
JOIN author AS A on A.author_id = L.author_id
GROUP BY Book
;
SELECT B.name AS Book, group_concat(A.name) AS Authors
FROM book_author AS L
JOIN book AS B ON B.book_id = L.book_id
JOIN author AS A on A.author_id = L.author_id
GROUP BY Book
ORDER BY Book DESC
;
(7) By Ryan Smith (cuz) on 2022-03-03 21:36:41 in reply to 5.0 [link] [source]
Fully agreed - if this turns out to be an actual real-world DB, Keith's suggestions are invaluable for good form, efficiency and maintainability.
(8) By Keith Medcalf (kmedcalf) on 2022-03-03 21:38:19 in reply to 5.0 [link] [source]
Also note that all the queries are incorrect. They should all be based off the following definition (view) if one wishes to have at all the data at once (note that you cannot retrieve a book with no authors, nor an author with no books; although this can be fixed, is it possible to have a book authored by no-one or a book authors with no books? -- this is what is called a "business rule" and has not been discussed and has major implications and can be easily handled).
create view all_books
as select book.book_id,
book.name as book_name,
author.author_id,
author.name as author_name
from book, author, book_author
where book.book_id == book_author.book_id
and author.author_id == book_author.author_id
;
(9.2) By Keith Medcalf (kmedcalf) on 2022-03-03 22:15:29 edited from 9.1 in reply to 8 [link] [source]
If you were to do this, then the following provides a view that permits authorless books and bookless authors by emulating
a full outer join:
create view all_books
as select book.book_id,
book.name as book_name,
author.author_id,
author.name as author_name
from book, author, book_author
where book.book_id == book_author.book_id
and author.author_id == book_author.author_id
UNION
select book.book_id,
book.name as book_name,
NULL as author_id,
NULL as author_name
from book
where not exists (
select *
from book_author
where book.book_id == book_author.book_id
)
UNION
select NULL as book_id,
NULL as book_name,
author.author_id,
author.name as author_name
from author
where not exists (
select *
from book_author
where author.author_id == book_author.author_id
)
;
If the view were used for all the queries, then the "business rule" (whatever it is) will be enforced automagically without having to remember to propagate it everywhere by manual methods.
(10) By Keith Medcalf (kmedcalf) on 2022-03-03 22:32:53 in reply to 9.2 [link] [source]
Note that if RIGHT OUTER JOIN
were supported by SQLite3 (it is not) this would simplify to:
create view all_books
as select book.book_id,
book.name as book_name,
author.author_id,
author.name as author_name
from book
left outer join book_author on book.book_id == book_author.book_id
right outer join author on author.author_id == book_author.author_id
;
Since LEFT
outer joins are supported and RIGHT
outer joins are not, then this would be perhaps a more efficient view (it should be noted, however, that this phrasing constrains the query planner, whereas the long form in the previous post does not).
create view all_books
as select book.book_id,
book.name as book_name,
author.author_id,
author.name as author_name
from book
left join book_author on book_author.book_id == book.book_id
left join author on author.authorid == book_author.author_id
UNION
select NULL as book_id,
NULL as book_name,
author.author_id,
author.name as author_name
from author
where not exists (
select *
from book_author
where author.author_id == book_author.author_id
)
;
(12) By Holger J (holgerj) on 2022-03-04 17:37:40 in reply to 8 [link] [source]
There is no == operator in SQL.
(13) By JayKreibich (jkreibich) on 2022-03-04 17:54:11 in reply to 12 [link] [source]
There is in SQLite’s dialect of SQL:
(6) By anonymous on 2022-03-03 21:28:58 in reply to 2 [link] [source]
thanks i needed that... just learning sqlite3...
(3) By JayKreibich (jkreibich) on 2022-03-03 17:49:15 in reply to 1 [link] [source]
This looks rather like a homework assignment.
(4) By Ryan Smith (cuz) on 2022-03-03 19:45:57 in reply to 3 [link] [source]
This looks rather like a homework assignment.
It would seem at first glance, but I doubt it. homework assignments are usually correctly stated, have sensible schemata and makes sense altogether.
This has an air of quickly fumbled-together analog to some real-world problem with broken schemata and nonsensical things like character names used for book titles, but done with obviously competent yet incomplete SQL knowledge.
Of course said real-world problem may well also be homework-related, but this feels more like someone who wants to ask "how do you add multiple items within a group together?" but decided to pose it as an analogous query, probably wishing to seem less uninformed and not-yet realizing that here we praise efforts to learn and do not belittle it - so there really is no need.
Or I could be wrong. :)
(11) By Trudge on 2022-03-04 17:27:36 in reply to 4 [link] [source]
I have several book and document sqlite DBs and typically have something like this
CREATE TABLE authors(id integer primary key autoincrement,author text,authorid integer);
CREATE TABLE keywords(id integer primary key autoincrement,keyword text,authorid integer,titleid integer);
CREATE TABLE IF NOT EXISTS "books" (
id
integer,
titleid
integer,
authorid
integer,
title
text,
pubyear
date,
filename
text,
notes
text, Birthdate text,
PRIMARY KEY(id
AUTOINCREMENT)
);
to handle subject / keyword and tie that to an author and book. Every book has an author, even if it's 'Unknown'.