Pergunta

mysql> SELECT * FROM nodes
    -> WHERE hostName IN ('localhost', 'm1iafw') OR
    ->        address IN ('localhost', 'm1iafw');
+----------------------+-----------+-----------+
| id                   | hostName  | address   |
+----------------------+-----------+-----------+
|  9131891219333790492 | NULL      | m1iafw    |
| 15289714606300179720 | localhost | NULL      |
| 15886756565768587967 | m1iafw    | 10.7.7.12 |
| 18400354826544934228 | m1iafw    | NULL      |
+----------------------+-----------+-----------+

Above is a simplified version of a query I'm working on. I would like to write this with one IN operator so I don't have to repeat list of host names multiple times. There could be hundreds of host names in the list, potentially.

What I want is something like:

SELECT * FROM nodes
 WHERE (hostName, address) INTERSECTS ('localhost', 'm1iafw');

I don't need the list of matching values like INTERSECT would provide. I just need a boolean result like with IN. Do the sets intersect or not.

Also, MySQL doesn't support the INTERSECT operator. Nor WITH. The usual advice is to rewrite the INTERSECT in a different form using joins, but I don't know how to do that since I'm not intersecting two tables.

Furthermore, what I really want to do is a bit more complex, even. Given the ID numbers of the nodes from the query up top, I want to search another table for matches, where any one of three columns might contain one of the matching IDs. With my hypothetical INTERSECTS operator I could write the query as:

SELECT * FROM alerts
 WHERE (analyzerNodeId, sourceNodeId, targetNodeId) INTERSECTS
           (SELECT id FROM nodes
             WHERE (hostName, address) INTERSECTS ('localhost', 'm1iafw'));

Any suggestions on how I can do this? My SQL-fu is not so strong.

Foi útil?

Solução

For such task you need to have "temporary" table, for mysql you can create it like this:

select 'localhost' as hostname
union all
select 'm1iafw'
union all
select ....

so, to fetch all distinct ID where either hostname or address is in this table you can use join syntax:

select id
from nodes as n
inner join (
    select 'localhost' as hostname
    union all
    select 'm1iafw'
) as q
on (n.hostName = q.hostname OR n.address = q.hostname)

then you can use this query as subquery for next operation:

SELECT *
FROM alerts as a
inner join
(
    select id
    from nodes as n
    inner join (
        select 'localhost' as hostname
        union all
        select 'm1iafw'
    ) as q
    ON (n.hostName = q.hostname OR n.address = q.hostname)
) as q2
ON (a.analyzerNodeId=q2.id OR a.sourceNodeId=q2.id OR a.targetNodeId=q2.id)

Outras dicas

You could perhaps implement using a FULL-TEXT index...

SELECT * FROM nodes
 WHERE MATCH (hostName,address ) AGAINST ('localhost m1iafw' IN BOOLEAN MODE);

http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top