2

It's not gentlemanly to not like many items. But I need a query that exclude many items (not in) using a list of many items using not like.

| source |
|========|
| danny  |
| ram    |
| nach   |
| boom   |
| trach  |
| banana |

| key_exclude    |
|================|
| danny          |
| ram            |

| like_exclude   |
|================|
| bo             |
| tr             |

The expected results:

| result |
|========|
| banana |
| nach   |

I want to something like that:

select * from source where key not in (select key from key_exclude.key) 
  and key not like in(like_exclude.key)

But it is doesnt work

I can do:

select * from source where key not in (select key from key_exclude.key) 
  and key not like '%bo%' and key not like '%tr%'

The only problem is that the 'like_exclue' may contain hundreds of records.

Aminadav Glickshtein
  • 23,232
  • 12
  • 77
  • 117

3 Answers3

2

Here is a solution query using subqueries:

select * 
from source AS s
where
    s.`key` not in( select k.`key` from key_exclude AS k ) AND
    NOT EXISTS( select 1 from like_exclude l WHERE s.`key` LIKE CONCAT('%', l.`key`, '%'));

Below is a full demo with data verified, also put on SQLFiddle by OP http://sqlfiddle.com/#!9/22fe8a/1/0

SQL:

-- Data
create table source(`key` char(20));
insert into source values
( 'danny' ),
( 'ram' ),
( 'nach' ),
( 'boom' ),
( 'trach' ),
( 'banana' );

create table key_exclude( `key` char(20));
insert into key_exclude values
( 'danny' ),
( 'ram' );

create table like_exclude( `key` char(20) );
insert into like_exclude values
( 'bo' ),
( 'tr' );

-- SQL Needed
select * 
from source AS s
where
    s.`key` not in( select k.`key` from key_exclude AS k ) AND
    NOT EXISTS( select 1 from like_exclude l WHERE s.`key` LIKE CONCAT('%', l.`key`, '%'));

Output:

mysql> select *
    -> from source AS s
    -> where
    -> s.`key` not in( select k.`key` from key_exclude AS k ) AND
    ->     NOT EXISTS( select 1 from like_exclude l WHERE s.`key` LIKE CONCAT('%', l.`key`, '%'));
+--------+
| key    |
+--------+
| nach   |
| banana |
+--------+
2 rows in set (0.00 sec)

Live Sample - SQL Fiddle: http://sqlfiddle.com/#!9/22fe8a/1/0

Aminadav Glickshtein
  • 23,232
  • 12
  • 77
  • 117
Dylan Su
  • 5,975
  • 1
  • 16
  • 25
2

Let me first say that it is indeed very ungentlemanly not to like so many things. But sometimes you just have to...

Anyways..one way to do it is to use RLIKE in combination with GROUP_CONCAT instead of LIKE. That would result in something like this. This will probably go 'wrong' if there are special regexp characters inside the like_exclude table. What this would do performance wise is up to you, and with a lot of values in the table you might have to alter the group_concat_max_len value :

SQLFiddle

SELECT 
   * 
FROM 
   source as s
WHERE 
   s.key NOT IN (SELECT ke.key FROM key_exclude as ke) 
   AND
   s.key NOT RLIKE (SELECT GROUP_CONCAT(le.key SEPARATOR '|') FROM like_exclude as le);
Poul Kruijt
  • 69,713
  • 12
  • 145
  • 149
1

You can use another not in to exclude the results that do answer the LIKE condition

select * from source
where key not in (select key from key_exclude.key) 
and key not in(select key from source
               where key LIKE (select concat('%',key,'%') from like_exclude.key)

But your query seems a little weird, you can't select from a column so I suspect you have to replace

 key_exclude.key -> key_exclude

And the other table too

like_exclude.key -> like_exclude
sagi
  • 40,026
  • 6
  • 59
  • 84