Home > other >  How to unescape % in LIKE clause
How to unescape % in LIKE clause

Time:01-26

I have my search patterns stored in database in patterns table. For example my table column name_pattern contains string 'Basic%'. I'd like to create dynamic search where search patterns will be fetched from name_pattern column.

So my SQL query should look something like:

SELECT *
FROM products
WHERE product_name LIKE name_pattern <-- somehow joined from patterns table

Seems that Oracle escapes % in my string but I want to take it unescapped in order my query to work like:

SELECT *
FROM products
WHERE product_name LIKE 'Basic%'

I found that my problem is with stable set of rows:

CREATE TABLE patterns(code CHAR(1),name_pattern VARCHAR2(20));
INSERT INTO patterns(code,name_pattern) VALUES('B','Basic%');
INSERT INTO patterns(code,name_pattern) VALUES('T','%thing');

CREATE TABLE products (id NUMBER,name VARCHAR2(20),code CHAR(1));
INSERT INTO products(id,name,found) VALUES(1,'Basic instinct',NULL);
INSERT INTO products(id,name,found) VALUES(2,'Basic thing',NULL);
INSERT INTO products(id,name,found) VALUES(3,'Super thing',NULL);
INSERT INTO products(id,name,found) VALUES(4,'Hyper instinct',NULL);

MERGE INTO products p USING
(
   SELECT code,name_pattern FROM patterns
) s
ON (p.name LIKE s.name_pattern)
WHEN MATCHED THEN UPDATE SET p.code=s.code;

SELECT * FROM products;

If my search patterns were Basic% and Super% in patterns table then this MERGE will work, but if my search patterns are Basic% and %thing, the second product should be marked with both codes 'B' and 'T' and that causes the error:

ORA-30926: unable to get a stable set of rows in the source tables

So my problem is not in (un)escaping :-(, sorry

CodePudding user response:

You don't have to (un)escape anything, I'd say.

SQL> with
  2  patterns (name_pattern) as
  3    (select 'Basic%'    from dual union all
  4     select '%foot%'    from dual
  5    ),
  6  products (id, name) as
  7    (select 1, 'Basic instinct' from dual union all
  8     select 2, 'Visual Basic'   from dual union all
  9     select 3, 'Littlefoot'     from dual union all
 10     select 4, 'Happy feet'     from dual
 11    )
 12  select b.id, b.name, a.name_pattern
 13  from products b join patterns a on b.name like a.name_pattern;

        ID NAME           NAME_P
---------- -------------- ------
         1 Basic instinct Basic%
         3 Littlefoot     %foot%

SQL>

Based on test case you provided: don't merge, update!

SQL> update products p set
  2    p.found = 1
  3    where exists (select null
  4                  from patterns o
  5                  where p.name like o.name_pattern
  6                 );

3 rows updated.

SQL> select * from products;

        ID NAME                      FOUND
---------- -------------------- ----------
         1 Basic instinct                1
         2 Basic thing                   1
         3 Super thing                   1
         4 Hyper instinct                0

SQL>

After you changed your mind (again), it is still update. Though, you didn't explain which code you want to take when there's multiple match (for example, product 2 matches both "Basic%" and "%thing") so I took any of them, using the min function.

SQL> update products p set
  2    p.code = (select min(o.code)
  3              from patterns o
  4              where p.name like o.name_pattern
  5             );

4 rows updated.

SQL> select * from products;

        ID NAME                 CODE
---------- -------------------- ----------
         1 Basic instinct       B
         2 Basic thing          B
         3 Super thing          T
         4 Hyper instinct       NULL

SQL>
  • Related