Is it possible to use SQLite pattern matching on a result set? - android

Is there a way I can apply the LIKE clause to a result set in SQLite? What I would like to accomplish is the following:
SELECT *
FROM MyTable
WHERE value LIKE
(
SELECT CASE
WHEN prefix IS NOT NULL THEN prefix || '?'
ELSE code END
FROM MyOtherTable
)
Adding the ? to the end of does not allow me to wildcard search by the prefix and the LIKE just ends up functioning like an IN clause.
Is there some way to achieve this, or alternatively a better way to achieve the same result?

Your primary issue is that ? is not a pattern matching character, rather that _ is for pattern matching any single character and % is for pattern matching a sequence of characters.
SQL As Understood By SQLite - expression - The LIKE, GLOB, REGEXP, and MATCH operators
However, you would also encounter issues if myOtherTable has multiple rows.
Consider the following :-
DROP TABLE IF EXISTS MyTable;
DROP TABLE IF EXISTS MyOtherTable;
CREATE TABLE IF NOT EXISTS MyTable (value TEXT);
CREATE TABLE IF NOT EXISTS MyOtherTable (prefix TEXT, code TEXT);
INSERT INTO MyOtherTable VALUES
(null,'mycode'),
('A','myothercode'),
('S',null)
;
INSERT INTO MyTable VALUES
('Something'), -- matched by S%
('A something'), -- matched by A%
('mycode is this'), -- never matched as characters after mycode
('Another'), -- matched by A%
('mycode') -- matched by mycode
;
-- Intermediate
SELECT CASE
WHEN prefix IS NOT NULL THEN prefix || '%'
ELSE code END
FROM MyOtherTable
;
SELECT *
FROM MyTable
WHERE value LIKE
(
SELECT CASE
WHEN prefix IS NOT NULL THEN prefix || '%'
ELSE code END
FROM MyOtherTable
);
The final result would be :-
A single row
mycode
That is only the first result of the subquery is considered.
If (null,'mycode'), is removed or commented out then the result would be :-
Two rows that match the now first A% i.e.
A something
Another
Removing or commenting out the first two (null,'mycode'), and ('A','myothercode'), results in the single row :-
Something

Related

sqlite, how replace a value from CSV saved in a column

I have a table in my android app with a column named tags, this column can contain one or multiple comma separated values, for example :
test1,test,test2
now I want to rename one of these values in entire table, I have the following query :
update mytable
set
tags = replace (tags, ',test,',',XXX,') // rename test with XXX
where
tags like '%,test,%'
this works fine as far as the value is in between commas.
How can I achieve this for the situation where my value is at the start or end of the csv or is the only value in csv.
You need to append commas at the start and at the end of the column and operate on that:
update mytable
set
tags = trim(replace(',' || tags || ',', ',test,', ',XXX,'), ',')
where
',' || tags || ',' like '%,test,%';
See the demo

Sqlite query to get list of next available characters after the matching search keyword

How to query sqlite database to get list of next available characters after the search keyword in a string field.
for example, if the search keyword is ’and’
and let the strings be a list of names like :
Andy Xyz
Andrew Xyz
Xyz Andon
Xyz Miranda
then i should get the characters [y,r,o,a].
I tried the query with substr(names,1,1), but substr needs to specify the start index which will be different in each strings. Is it possible to fetch these characters using sqlite query?
You need substr() and instr():
select
substr(names, instr(lower(names), lower('and')) + length('and'), 1) nextchar
from tablename
where
names like '%' || 'and' || '_%'
See the demo
You can replace 'and' with any string you wish in the above query.
You could utilise the instr function to ascertain the start of the substr e.g. :-
SELECT *, substr(names,instr(lower(names),'and') + length('and'),1) AS onechar
FROM mytable WHERE names LIKE ('%and%');
A working example :-
DROP TABLE IF EXISTS mytable;
CREATE TABLE IF NOT EXISTS mytable (names TEXT);
INSERT INTO mytable VALUES('Andy Xyz'),('Andrew Xyz'),
('Xyz Andon'),('Xyz Miranda');
SELECT *, substr(names,instr(lower(names),'and') + length('and'),1) AS onechar FROM mytable WHERE names LIKE ('%and%');
This results in :-
as per your expected results.

Search String in column value of Sqlite

I am trying to search a String in column of my table .The values are stored in
column in this format
My Search String is similar as above. i.e: comma separated String
My query is to find out whether any value in search String is present is my column or not.
Things I have Tried:
using Like : Like does it.But it matches individual values i.e for 3 search string values I have to make 15 like condition(costly for large table)
SELECT * from A WHERE mycol LIKE 'myval,%' or mycol LIKE '%, myval,%' or mycol or LIKE '%, myval'
using instr function : instr matches the String but only the First Occurance.
e.g: select * from A where instr ('123' ,'12')
using In : This donot search within the String .But Matches the values individually.
I have tried Like function Like(X , Y) from docs Here
So my Question is there a way , instead of Individually searching my search string in the column using Like Operator or In function . I could search my values values in single query something like combination of In and Any(not supported in Sqlite) function does in other Db
i.e select * from A where Any('my search string') in ('my column value')
Any Answer or comment is HIGHLY Appreciated.Hoping for reply.
You have problems because your database is not properly normalized.
To have multiple search IDs for each MyTable row, create a second table that can have multiple rows, with one search ID in each row:
CREATE TABLE MyTable (
MyTableID INTEGER PRIMARY KEY,
[...]
);
CREATE TABLE MyTableSearchIDs (
MyTableID INTEGER REFERENCES MyTable(MyTableID),
SearchID INTEGER -- or TEXT or whatever
);
To search for a MyTable row, search its ID first:
SELECT *
FROM MyTable
WHERE MyTableID IN (SELECT MyTableID
FROM MyTableSearchIDs
WHERE SearchID = 'myvalue')
The same can be done with a join:
SELECT MyTable.*
FROM MyTable
JOIN MyTableSearchIDs USING (MyTableID)
WHERE MyTableSearchIDs.SearchID = 'myvalue'

I'm trying to compile a query to cope with the no rows found, but using SELECT CASE blocks bindargs

with a simple query, using bindargs works fine, but as soon as I include select case ..... in the query it always fails "Can't pass bindargs for this sql", if I test with all the '?'s replaced with fixed values, it compiles and runs OK, so it does seem to be that argument binding cannot cope with selects embedded inside select case. Is this true?
the query I am compiling is:
(SELECT CASE
WHEN ((SELECT _id FROM point2D WHERE x=? AND y=?) IS NULL ) THEN 0
ELSE (SELECT _id FROM point2D WHERE x=? AND y=? LIMIT 1))
and the table is setup with
create table if not exists point2D ( _id INTEGER PRIMARY KEY AUTOINCREMENT,
x REAL, y REAL )
I only want a single compiled query that returns the key to an existing matching record, or a known 'its not there' value, but of course a simple query like
SELECT _id FROM point2D WHERE x=? AND y=? LIMIT 1
will cause an exception with simpleQueryForLong when there is nothing found (which is quite expensive in cpu time)
I cannot use insert or update, because update actually replaces the old row with a new row (and hence a new _id) which screws up all the other stuff pointing to this.
You have kept the actual parameter code a secret, but I'd guess that you provide only two parameters although the query has four.
You can use one parameter multiple times if you give it a name or a number:
(SELECT CASE
WHEN ((SELECT _id FROM point2D WHERE x=?1 AND y=?2) IS NULL ) THEN 0
ELSE (SELECT _id FROM point2D WHERE x=?1 AND y=?2 LIMIT 1))
However, for this particular query, you'd better use the ifnull function:
(SELECT ifnull((SELECT _id FROM point2D WHERE x=? AND y=?), 0))
(And I doubt that the outer subquery is actually needed.)

Ignore accents SQLite3

How do I make a SELECT with a LIKE clause ignoring accents on SQLite3?
PS: It's for Android build-in SQLite support.
There is a solution, it is not elegant, but it works on Android.
The function REPLACE can replace the accented character by the normal character. Example:
SELECT YOUR_COLUMN FROM YOUR_TABLE WHERE replace(replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace( lower(YOUR_COLUMN), 'á','a'), 'ã','a'), 'â','a'), 'é','e'), 'ê','e'), 'í','i'),
'ó','o') ,'õ','o') ,'ô','o'),'ú','u'), 'ç','c') LIKE 'SEARCH_KEY%'
Or use unicode:
SELECT YOUR_COLUMN FROM YOUR_TABLE WHERE replace(replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace( lower(YOUR_COLUMN), '\u00E1','a'), '\u00E3','a'), '\u00E2','a'), '\u00E9','e'), '\u00EA','e'), '\u00ED','i'),
'\u00F3','o') ,'\u00F5','o') ,'\u00F4' ,'o'),'\u00FA','u'), '\u00E7' ,'c') LIKE 'SEARCH_KEY%'
Where SEARCH_KEY is the key word that you wanna find on the column.
There has been a similar question here.
They said it is not really possible on Android, but there is a workaround with an additional normalized column.
You can a create a mask column and update after insert values in to table with a trigger.
-- Table
CREATE TABLE IF NOT EXISTS mytable (
id TEXT PRIMARY KEY,
description TEXT default '',
description_mask TEXT default ''
);
-- Trigger
CREATE TRIGGER IF NOT EXISTS mytable_in AFTER INSERT ON mytable
BEGIN
UPDATE mytable
SET description_mask =
lower(
replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(
NEW.description,
'á','a'), 'ã','a'), 'â','a'), 'é','e'), 'ê','e'), 'í','i'), 'ó','o') ,'õ','o') ,'ô','o'),'ú','u'),'ç','c'),'ñ','n'),
'Á','a'), 'Ã','a'), 'Â','a'), 'É','e'), 'Ê','e'), 'Í','e'), 'Ó','o') ,'Õ','o') ,'Ô','o'),'Ú','u'),'Ç','c'),'Ñ','n')
)
WHERE id = NEW.id;
END;
-- Select example
SELECT * FROM mytable WHERE (description LIKE '%acido%' OR description_mask LIKE '%ácido%');

Categories

Resources