Query where column value contains specific word - mysqli

I am doing a query using LIKE to pull results that contain a specific name:
SELECT ID FROM accessories WHERE ItemName LIKE '%stripe%'
The only problem is that I'm getting results which include the word "stripe" as well as "stripes", "striped", etc.
How can I modify this query to pull only results where an individual word equals exactly "stripe"?

try
SELECT ID FROM accessories WHERE ItemName LIKE '%stripe %'
or
SELECT ID FROM accessories WHERE ItemName LIKE '%stripe%' and ItemName NOT LIKE '%stripes%'

Related

How to speed up this Postgres query by reducing the number of rows it has to search through before it searches?

Context:
I have three Postgres tables:
authors - stores the id, author's full name, credentials, and awards
books - stores the id, title, book-length, summary, and an image of the front cover
authorBookRelations - connects Authors and Books by storing the author_id and book_id
An author can be connected to any book, but books are not connected. Books can have the same name, but each has its own id that is unique. Multiple authors can author a single book.
My question:
If I want to get all titles that match a given list of titles and are by a specific author what would be the best way to do that?
What I have so far:
Currently, I do two SELECT queries and a filtering function to "join" the two queries.
SELECT query #1 - get all of the book_ids associated with a particular author:
SELECT book_id FROM authorBookRelations WHERE author_id = 5
SELECT query #2 - get all of the titles that are in a given list of titles:
SELECT * FROM books WHERE title IN ('arbitraryTitle_1', arbitraryTitle_2, etc.)
Filter function (python) - filter titles for any that are not written by that specific author:
filtered_list = [x for x in query_2_results if x.id in query_1_results]
I get the correct books with this method, but can't help but feel that this is not a good way to do it/won't scale well. What would you suggest as a way to speed up this query? Instead of two separate db calls and a filtering function, could I do it all in one call by searching the list of titles against the filtered rows in table "books" that were filtered by the output from the query against authorBookRelations? ... that was horribly worded ... so something like this:
SELECT *
FROM (
SELECT book_id
FROM authorBookRelations
WHERE author_id = 5) AS foobar
WHERE title IN ('arbitraryTitle_1', arbitraryTitle_2, etc.)
UPDATE:
Trying out this seems to have cut my total query/processing time by half:
select *
from (select *
from books
where id in (
select book_id
from authorBookRelations
where author_id = 5
)) as foo
where foo.title in ('arbitraryTitle_1', 'arbitraryTitle_2', etc.)
The problem of performances will be on the "IN" operator, if the list has a great number of items...
For two or three sometime an index can be used by PG for seeking the data.
But when there is much more items, a scan will be the only solution...
If you want to speed up this query, just use a temporary table to INSERT your data into, the add an index and rewrite the query with a join between this temp table and your original query...

Get entire record with max field for each group

There are a lot of answers about this problem, but none of them retrieves the entire record, but only the ID... and I need the whole record.
So, I have a table status_changes that is composed of 4 columns:
issue_id : the issue the change refers to
id: the id of the change, just a SERIAL
status_from and status_to that are infact the status that the issue had before, and the status that the issue got then
when that is a timestamp of when this happened
Nothing too crazy, but now, I would like to have the "most recent status_change" for each issue.
I tried something like:
select id
from change
group by issue_id
having when = max(when)
But this has obviously 2 big problems:
select contains fields that are not in the group by
2 having can't contains aggregate function in this way
I thought of "ordering every group by when and using something like top(1), but I can't figure out how to do it...
Use PostgreSQL's DISTINCT ON:
SELECT DISTINCT ON (issue_id)
id, issue_id, status_from, statue_to, when
FROM change
ORDER BY issue_id, when DESC;
This will return the first result (the one with the greatest when) for each issue.

postgres: Search for multiple words in string

I'm implementing a rudimentary form of search for my company backoffice system. I would like to find all products names that contain all words in a search query.
So if I have these two products:
Deodorant with cucumber flavor
Deoderant with apple flavor
the search query: cucumber deoderant should match only Deoderant with cucumber flavor.
I can make it work for the query deoderant cucumber like so:
SELECT product_name FROM products WHERE name ~* regexp_replace('deoderant cucumber', '\s+', '.*', 'g');
but this approach does not work when the order is not the name in the query and the product name.
I know that this is possible by doing something like
SELECT product_name FROM products WHERE name ~* 'deoderant' AND name ~* cucumber';
but I would ideally like to stay away from string interpolation as it becomes a bit messy in my current environment.
Is there another, more elegant way to do this?
You could convert the value into an array and then use the "contains" operator #> with the words you are looking for:
SELECT product_name
FROM products
WHERE regexp_split_to_array(lower(name), '\s+') #> array['deodorant', 'cucumber'];
Online example: https://rextester.com/GNL7374

Is it possible to merge two simple DB queries to get a single reply containing a hash

in my blog-like app, i have two separate queries;
Select id, title, content from posts where id ='$a_post_id'
and
Select tagname, tagscore from tags where postid ='$a_post_id'
Since my db is hosted on a different server from my app, my major performance issue is with the server request roudabout for both the queries.
I was wondering if I can merge the two queries into a single query so that the expected output is
postdetails for '$a_post_id'= id, title, content, tags (hash of tagname, tagscore)
Something similar to a join but where the rows are asymmetrical. Or join returning hashes...
Also, this sounds like a great fix to a simple issue, but am I missing something here? Assuming that this solution is possible, are there any obvioud cons associated with it?
If a JSON key/value pair is OK, you can something like this:
select p.id, p.title, p.content,
jsonb_object_agg(t.tagname, t.tagscore) as tags
from posts p
left join tags t on t.postid = p.id
where p.id ='$a_post_id'
group by p.id;
The above assumes that posts.id is defined as the primary key
Online example: https://rextester.com/RDQX27041

Sphinx Filtering based on categories using OR

I have the following text fields I search with Sphinx: Title, Description, keywords.
However, sometimes things are narrowed down using categories. We have 3 category fields: CatID1, CatID2 and CatID3.
So, for example, I need to see if the word "Kittens" is in the Title, Description, or Keywords, but I also want to filter so that only items that have the categories (Animals - ID Number 8) or (Pets - ID Number 9) or (Felines - Category ID Number 10) in either of those CatID fields.
To clarify, only show items that have a 8,9 or 10 in CatID1, 2 or 3.
Any ideas on how I would accomplish this using sphinx filtering or searching the CatID1 fields as keywords?
Note: I am able to filter and it works great only using one category, i.e:
if(!empty($cat_str)) {
$cl->SetFilter( 'catid1', array( $cat_str ));
}
Thanks!
Craig
SetFilter takes an array. In your example you are putting $cat_str into an array. A array of one item.
So you just needs to build array with all the ids.
$cl->SetFilter( 'catid', array( $cat1, $cat2, $cat3 ));
But thats not very flexible. So you probably build the array dynamically, rather than hard-coded like that. But thats upto your application how to build the array.
But also storing the ids, in three sperate attributes, makes it hard to search. Notice in the above example, just noticed a attribute called catid. This would be a single multi-value attribute, that contains the ids from all three cat fields. That way its easy to search for ids in ANY of the columns at once.
http://sphinxsearch.com/docs/current.html#mva
if using a sql source, could do with something like
sql_query = SELECT id, title ... , CONCAT_WS(',', CatID1, CatID2 and CatID3) as catid FROM ...
sql_attr_multi = uint catid from field;