3

Can I have a condition of something like this:

SELECT * FROM table WHERE ? LIKE (column || '%')

Where the ? is a string parameter value. For example, these parameter value ? should return true when column is equal to /admin/products

/admin/products/1
/admin/products/new
/admin/products/1/edit

Is this possible?

Update: Added test case.

Basically, the where clause would render like this:

1.  ? LIKE (column || '%')
2.  '/admin/products/1' like ('/admin/products' || %)
3.  '/admin/products/1' like ('/admin/products%')

But it always return false for me.

These queries works fine though:

column = '/admin/products' --returns true
column = '/admin/products/1' --returns false
column LIKE '/admin/prod%' --returns true

The problem arises when I put the parameter ? before the LIKE clause. Is it not allowed?
If it's not, are there any workarounds for this?

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
John Isaiah Carmona
  • 5,260
  • 10
  • 45
  • 79

3 Answers3

2

The query:

SELECT * FROM table WHERE ? LIKE (col || '%');

can be rewritten as (Postgres and MySQL):

SELECT * FROM table WHERE col = left(?, length(col));

As commented, the first form should work as well. It can be tricky, though, because characters with special meaning for LIKE (at least _%\) in the column would have to be escaped. If you want it to work with both MySQL and Postgres, you'll have to observe special characters in both implementations. So the 2nd form is much less error-prone on principal.

Performance

Neither of these queries can use an index on col, both are not sargable. The problem can be re-assessed as finding all possible prefixes to the given search pattern ?, which can be optimized in a similar fashion like in this related answer (for Postgres) on dba.SE:

Community
  • 1
  • 1
Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
1

Replacing

SELECT * FROM table WHERE ? LIKE (column || '%')

by

SELECT * FROM table WHERE ? LIKE CONCAT(column, '%')

works for me.

Maybe || is used as logical or-operation instead of concatenation.

Julian Ladisch
  • 1,367
  • 9
  • 10
  • Thanks! Will it work on postgre too? Our production database is actualy on postgre, and our dev environment is on MySQL. – John Isaiah Carmona Nov 18 '14 at 09:42
  • @JohnIsaiahCarmona: I would strongly suggest to use the same RDBMS for dev & production, or you'll keep running into "surprising" problems. There is also a [`concat()` function in Postgres](http://www.postgresql.org/docs/current/interactive/functions-string.html#FUNCTIONS-STRING-OTHER) but `||` is the standard-SQL concatenation operator. And [the name is not "postgre"](https://wiki.postgresql.org/wiki/Identity_Guidelines). – Erwin Brandstetter Nov 18 '14 at 10:08
  • @ErwinBrandstetter They actually state that *All other names are incorrect, especially Postgre* in their documentation, lol, sorry. My colleagues was also using PostgreSQL but I need a better IDE for my database (on-table editing and stuff) which I can't find for PostgreSQL (am using MySQL Workbench). But I personally think dolphins and elephants are the same ;) – John Isaiah Carmona Nov 18 '14 at 10:19
  • 1
    @John PostgreSQL since 9.1 also has a `concat` function, working example: http://sqlfiddle.com/#!15/07da7/1 – Julian Ladisch Nov 18 '14 at 10:22
0

Works for me.

PREPARE withparam(text) AS SELECT $1 LIKE ('/admin/products' || '%');

EXECUTE withparam('/admin/products/1');

returns true.

Your test case doesn't appear to accurately reflect the actual issue at hand.

Craig Ringer
  • 307,061
  • 76
  • 688
  • 778
  • Sorry that was just a typo. :p Already fixed. Thanks for pointing that out. – John Isaiah Carmona Nov 18 '14 at 08:48
  • @JohnIsaiahCarmona I'm still convinced your real issue is elsewhere and the testcase doesn't really reflect what you're doing. It makes no sense that `select '/admin/products/1' like ('/admin/products%')` could return false for you. – Craig Ringer Nov 18 '14 at 08:51
  • I actually checked the generated SQL query by debugging and it is `'/admin/products/1' like (url || '%')` but it really returns false. I think the problem is on the implementation of the `like` condition not allowing the table name after it. But running your query on MySQL returns true. Thanks for helping though! I really appreciate it! – John Isaiah Carmona Nov 18 '14 at 08:55