How to select multiple 'LIKE' results
(1.1) By Trudge on 2022-09-23 17:42:42 edited from 1.0 [link] [source]
I have a database of articles, some of which have several keyword links. I would to create a select statement that gets an article with keyword1 AND keyword1.
CREATE TABLE sqlite_sequence(name,seq);
CREATE TABLE IF NOT EXISTS "keywords" (
`id` integer NOT NULL,
`keyword` text,
`authorid` integer,
`titleid` integer,
PRIMARY KEY(`id` AUTOINCREMENT)
);
CREATE TABLE IF NOT EXISTS "authors" (
`id` integer NOT NULL,
`author` text,
`authorid` integer,
`titleid` integer,
PRIMARY KEY(`id` AUTOINCREMENT)
);
CREATE TABLE IF NOT EXISTS "docs" (
`id` INTEGER,
`authorid` INTEGER,
`title` TEXT,
`source` TEXT,
`pubyear` INTEGER,
`notes` TEXT,
`filename` TEXT,
`issue` TEXT,
`titleid` INTEGER,
PRIMARY KEY(`id` AUTOINCREMENT)
);
I have a query with an OR but can't seem to get it working with an AND. Of course this doesn't work because a keyword can't be one thing AND another. The logic of how this can work stumps me.
select title,keywords.keyword from docs
join keywords on docs.authorid=keywords.authorid
and docs.titleid=keywords.titleid
where keyword in("Geometry")
or keyword in ("Mathematics")
order by title;
Is it possible to get a query working with keyword1 AND keyword2?
(2) By Keith Medcalf (kmedcalf) on 2022-09-23 18:10:49 in reply to 1.1 [link] [source]
Obviously not. keyword is single attribute of a single row of a single table and cannot have more than one value at a time.
However, you may find all the "stuffs" with keyword1 and then all the same "stuffs" that have keyword2, and then INTERSECT them to find the "common stuffs".
select title
from docs
join keywords
on docs.authorid == keywords.authorid
and docs.titleid == keywords.titleid
where keyword == 'Geometry'
INTERSECT
select title
from docs
join keywords
on docs.authorid == keywords.authorid
and docs.titleid == keywords.titleid
where keyword == 'Geometry'
order by title;
NOTE: Fixed Quotes: " is for identifiers, ' is for text strings
NOTE: Fixed keyword in (entry) to keyword == entry
It would probably be perspicacious to normalize your database.
(3) By Jon (gocoder) on 2022-09-23 18:14:33 in reply to 1.1 [source]
I was also able to accomplish this with a CTE. Certainly not saying this is a better solution.
WITH q AS ( SELECT k1.titleid, k2.authorid FROM keywords k1 INNER JOIN keywords k2 ON k1.titleid=k2.titleid AND k1.authorid=k2.authorid WHERE k1.keyword = 'Geometry' AND k2.keyword='Mathematics' ) SELECT title FROM docs JOIN q ON docs.authorid=q.authorid AND docs.titleid=q.titleid ORDER by title;
(4) By David Raymond (dvdraymond) on 2022-09-23 18:42:02 in reply to 1.1 [link] [source]
Two possibilities Sub-select: select title from docs where ( select count(*) from keywords where authorid = docs.authorid and titleid = docs.titleid and keyword in ('Geometry', 'Mathematics') --Your list of keywords here ) = 2 --How many keywords are in your list ; CTE with wanted_keywords (keyword) as (values ('Geometry'), ('Mathematics')) select title from docs inner join keywords on keywords.authorid = docs.authorid and keywords.titleid = docs.titleid and keyword in wanted_keywords group by docs.id having count(*) = (select count(*) from wanted_keywords) ;
(5) By Keith Medcalf (kmedcalf) on 2022-09-23 19:23:56 in reply to 1.1 [link] [source]
If the tables were normalized (such that the keyword 'Geometry' is the same keyword when attached to title 'Jiggling Ducks' and 'Dumpy frumps'. As in perhaps:
create table keyword
(
id integer primary key,
keyword text collate nocase unique
) strict;
create table docs
(
id integer primary key,
authorid INTEGER,
title TEXT,
source TEXT,
pubyear INTEGER,
notes TEXT,
filename TEXT,
issue TEXT,
titleid INTEGER
);
create table linkage
(
keyid integer not null references keyword,
docid integer not null references docs,
primary key (keyid, docid),
unique (docid, keyid)
) without rowid;
THen one could use something like:
select *
from docs
where id in ( select docid from linkage, keywords where keyid==id and keyword = 'keyword1'
intersect
select docid from linkage, keywords where keyid==id and keyword = 'keyword2'
intersect
...
)
;
(6) By Trudge on 2022-09-23 20:30:28 in reply to 1.1 [link] [source]
I believe I have solved my problem using views.
create temp view geo as select title,keyword from docs,keywords
where keyword like "%Geometry%"
and docs.authorid=keywords.authorid
and docs.titleid=keywords.titleid;
create temp view math as select title,keyword from docs,keywords
where keyword like "%Mathematics%"
and docs.authorid=keywords.authorid
and docs.titleid=keywords.titleid;
Then my query gave me 2 results:
select geo.title,geo.titleid,geo.keyword,math.title,math.titleid,math.keyword from geo,math
where geo.title=math.title;
title|keyword|title|keyword
Curves of Constant Width|Geometry|Curves of Constant Width|Mathematics
1 Peg in 3 Holes|Geometry|1 Peg in 3 Holes|Mathematics
After checking the DB I'm convinced these are the only titles that have both 'Geometry' AND 'Mathematics' as keywords.
What a great day!
(7) By Trudge on 2022-09-23 20:45:59 in reply to 6 [link] [source]
Wow, some excellent suggestions here. Thank you all for the inputs. My use of sqlite has been rather simplistic so far, and this was a good exercise for me.