sql where closure with modified column value - sqlite

I have a master table containing URLs:
CREATE TABLE IF NOT EXISTS MasterTable (url, masterId, PRIMARY KEY(url), UNIQUE(masterId));
An url string looks like this: file:///Users/user1/Pictures/rubus_and_apple.jpeg.
Now I want to lookup on the url column but only on the filename rubus_and_apple and not on all url string. (Meaning only on the last component of the url w/o extension).
For example I want to look the keyword rubus and get the url:file:///Users/user1/Pictures/rubus_and_apple.jpeg.
I need my query to be like:
SELECT masterId
FROM MasterTable
WHERE <url last component w/o extension> LIKE '%/rubus%';
How can I do so?

You could use LIKE:
SELECT masterId
FROM MasterTable
WHERE url LIKE '%/rubus.%';
Please note that this expression is not-SARGable so it won't use index.
EDIT:
WITH MasterTable(MasterId, url) AS(
VALUES(1, 'file:///Users/user1/Pictures/rubus_and_apple.jpeg')
)
SELECT *
FROM MasterTable
WHERE REPLACE(url,RTRIM(url,REPLACE(url,'/','')),'') LIKE '%' || 'rubus' || '%';
-- part of string after last /
db<>fiddle demo

Related

Extract from last slash till the end in sqlite

I have a table with an url column with urls like so:
https://shop.domain.com/product/12345/this-is-great-product
I need to extract the last part from the last slash to the end:
this-is-great-product
I was planning in using something REGEXP_SUBSTR but its an extension that I don want to install.
How can i do this in SQLite version 3.39.4 ?
You can use JSON: convert your delimited string (url) into a valid JSON array, then take the last element:
CREATE TABLE IF NOT EXISTS urls(url);
DELETE FROM urls;
INSERT INTO urls(url) VALUES ('https://shop.domain.com/product/12345/this-is-great-product');
SELECT json_extract('["' || replace(url, '/', '", "') || '"]', '$[#-1]') AS suffix FROM urls;
See the fiddle.

SQLite full-text search with multiple tokens using a prepared statement

Given the following tables:
create table index(name text, docid int);
create virtual table docs using fts4();
The following query works as intended when querying for a single token (for example: march, or bad):
select name from index where docid in (select docid from docs where docs match ?)
But how can I query for more than one token (say, bad bed)? Binding the string bad bed directly does not work (always selects nothing), neither surrounding the placeholder or the string with double quotes, nor using AND to MATCH each token separetly (this last one throws an error).
Using intersect does work, but it's clunky and innefficient when searching for many tokens:
select name from index where docid in (
select docid from docs where docs match ?
intersect
select docid from docs where docs match ?
intersect
...
)
Each ? is paired with a single token.
You can use the concatenation operator || in sqlite. '' would be the empty string
SELECT * FROM table WHERE docs MATCH '' || ? || ' ' || ? || ' ' || ? || ''
Make sure there is a space between every token or an ' AND '.
Update
Actually it doesn't work. It seems there are tokenator issues with this approach. Its better to concatenate all the tokens with the space and bind the resulting string with a single '?'
There are operators within the match syntax in FTS so you can use AND, OR and NOT.
See here for documentation
e.g.
-- Return the docid values associated with all documents that contain the
-- two terms "sqlite" and "database", and/or contain the term "library".
SELECT docid FROM docs WHERE docs MATCH 'sqlite AND database OR library';

How to search my database by using an array of words?

I'm attempting to setup a search function from a string a user types. (ex: "John Doe" or "Doe, John")
I was thinking I would use Replace(SearchString, ",", "") to get rid of the commas the user might enter, and then use Split(SearchString, " ") to get all the words into an array. Once they're in the array I would execute a Stored Procedure on each of the terms and build a DataTable with the results.
Below is what I'm wanting to use for executing my stored procedure.
oCommand = DataAccess.GetSQLCommand("MyStoredProcedure", CommandType.StoredProcedure, SourceServer.ConnectionLocal)
oCommand.Parameters.AddWithValue("#MySearchString", SearchString)
oAdapter = New SqlDataAdapter(oCommand)
oAdapter.Fill(MyDataTable)
Now I'm thinking the "SearchString" I will assign while looping through my array of words... but this doesn't seem like the right way to do this. Maybe it is but I don't know how to append my next result to the previous DataTable either.
There are some great ideas for using arrays and Lists in SQL Server on this page - http://www.sommarskog.se/arrays-in-sql-2005.html
I personally find the XML method the most useful;
http://www.sommarskog.se/arrays-in-sql-2005.html#XML
An example of how I've used this in the past is;
DECLARE #indata nvarchar(max)
DECLARE #hDoc int
SET #indata = '
<ROOT>
<SearchTerm code="Test search term"></SearchTerm>
<SearchTerm code="Other search term"></SearchTerm>
<SearchTerm code="Next search term"></SearchTerm>
</ROOT>'
CREATE TABLE #searchTerm (
code varchar(40)
)
EXEC sp_xml_preparedocument #hDoc OUTPUT, #indata
INSERT Into #searchTerm
SELECT code
FROM OPENXML(#hDoc, '/ROOT/SearchTerm',1)
WITH (code varchar(50))
EXEC sp_xml_removedocument #hDoc
-- Use the data in #searchTerm as needed in your query
SELECT * FROM MyTable WHERE searchValue IN (SELECT code FROM #searchTerm)
DROP TABLE #searchTerm
Try passing in the comma separated values in as a single string of nvarchar. Then use the SELECT FROM WHERE IN structure within your stored procedure. Create the sql command wwithin your stored procedure by concatenation and then call EXEC #sql
Declare #sql =
'SELECT * FROM tbl
WHERE person IN(' + #Application + ')'
exec(#sql)
Beware, if your list of search criteria is large this may not be the best solution for you.
Note that the commas should be between the full names not the first name and last name.

In query in SQLite

"IN" query is not working. Please guide me if i am wrong.
KaizenResultsInformationTable is MasterTable having field "recordinfo", this field contains Child table Ids as string.
kaizenResultsRecordInformationTable is Childtable having field "recordId".
I have to match records of child.
Query:
select recordinfo from KaizenResultsInformationTable
Output: ;0;1;2;3;4;5;6;7;8;9;10
Query:
select substr(replace(recordinfo,';','","'),3,length(recordinfo))
from KaizenResultsInformationTable`
Output: "0","1","2","3","4","5"
This query is not working:
select * from kaizenResultsRecordInformationTable
where substr(recordid,0,2) in (
select substr(replace(recordinfo,';','","'),3,length(recordinfo))
from KaizenResultsInformationTable
)
This query is working:
select * from kaizenResultsRecordInformationTable
where substr(recordid,0,2) in ("0","1","2","3","4","5")
You can't use in like that. In your second query, you are passing in a single string containing a comma-separated list of values.
It is better to represent a list of IDs as one record for each value.
Also, I'm not sure why you are taking a substring of your recordid. You should usually be storing one value per column.
However, if you can't change the schema, you can use string matching with 'like' instead of 'in'. Something like this should work:
select a.* from kaizenResultsRecordInformationTable a
join KaizenResultsInformationTable b
on (';'+b.recordinfo+';') LIKE ('%;'+trim(substr(recordid,0,2))+';%')
So if your recordinfo looks like 1;2;3;4;5;6, and your substr(recordid,0,2) looks like 1, this will include that row if ";1;2;3;4;5;6;" LIKE "%;1;%", which is true.

Using prepared statements and full-text-search in SQLite

I'm using the SQLite C interface to write an application. Since I like security, I'm using prepared statements to query the database. In one such query, I'm selecting rows from a virtual database using the MATCH keyword for full-text-searching. Here's an example:
SELECT * FROM Emails
WHERE ( Subject LIKE ?001 OR ?001 IS NULL )
AND ( Author LIKE ?002 OR ?002 IS NULL )
AND ( Body MATCH ?003 OR ?003 IS NULL )
This allows the user to enter any terms (Subject, Author, or Body) individually or in any combination to do a search. Any term that isn't entered, I'll bind NULL to that parameter. The problem with that statement is that you can't use the OR keyword with the MATCH keyword. I'm looking for a statement I can use with the MATCH keyword to return all rows if not searching in the Body column. Is there such a statement?
I suggest the following:
SELECT * FROM emails
WHERE ...
AND ( CASE (SELECT COUNT(*) FROM emails WHERE body MATCH ?003)
WHEN 0 THEN 1
ELSE body MATCH ?003
END )
I ended up modifying the SQL statement at runtime to replace MATCH with LIKE '%'. Not very elegant, but it works for now.

Resources