Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como usar regexp nos resultados de uma subconsulta?


Tente uma destas consultas:
SELECT a.phone_no
FROM admission a
JOIN users u on a.phone_no LIKE concat(u.phone_no, '__')
WHERE u.phone_no REGEXP  '^(99)+[0-9]+$'

ou
SELECT a.phone_no
FROM admission a
JOIN users u on a.phone_no REGEXP concat('^', u.phone_no, '[0-9]{2}$')
WHERE u.phone_no REGEXP  '^(99)+[0-9]+$'

Se o número de "dígitos finais" não for fixo, você também pode usar:
LIKE concat(u.phone_no, '%')

ou
REGEXP concat('^', u.phone_no, '[0-9]*$')

Mas neste caso você pode precisar usar SELECT DISTICT a.phone_no se for possível que um users.phone_no é uma subsequência de outro users.phone_no (por exemplo, 99123 e 991234).

Atualizar

Depois de executar alguns testes com 10K linhas para tabela de usuários e 100K linhas para tabela de admissão cheguei à seguinte consulta:
SELECT a.phone_no
FROM admission a
JOIN users u 
    ON  a.phone_no >= u.phone_no
    AND a.phone_no < CONCAT(u.phone_no, 'z')
    AND a.phone_no LIKE CONCAT(u.phone_no, '%')
    AND a.phone_no REGEXP CONCAT('^', u.phone_no, '[0-9]*$')
WHERE   u.phone_no LIKE  '99%'
    AND u.phone_no REGEXP  '^(99)+[0-9]*$'
UNION SELECT 0 FROM (SELECT 0) dummy WHERE 0

violino

Desta forma você pode usar REGEXP e ainda tem um ótimo desempenho. Essa consulta é executada quase instantaneamente no meu caso de teste.

Logicamente, você só precisa das condições REGEXP. Mas em tabelas maiores, a consulta pode expirar. O uso de uma condição LIKE filtrará o conjunto de resultados antes da verificação de REGEXP. Mas mesmo usando LIKE a consulta não funciona muito bem. Por alguma razão, o MySQL não usa uma verificação de intervalo para a junção. Então eu adicionei uma verificação de intervalo explícita:
    ON  a.phone_no >= u.phone_no
    AND a.phone_no < CONCAT(u.phone_no, 'z')

Com esta verificação você pode remover a condição LIKE da parte JOIN.

A parte UNION é um substituto para DISTECT. O MySQL parece traduzir DISTINCT em uma instrução GROUP BY, que não funciona bem. Usando UNION com um conjunto de resultados vazio, forço o MySQL a remover duplicatas após o SELECT. Você pode remover essa linha se usar um número fixo de dígitos à direita.

Você pode ajustar os padrões REGEXP às suas necessidades:
...
    AND a.phone_no REGEXP CONCAT('^', u.phone_no, '[0-9]{2}$')
...
    AND u.phone_no REGEXP  '^(99)+[0-9]{8}$'
...

Se você precisar apenas do REGEXP para verificar o comprimento do phone_no, também poderá usar uma condição LIKE com o espaço reservado '_'.
    AND a.phone_no LIKE CONCAT(u.phone_no, '__')
...
    AND u.phone_no LIKE '99________$'

ou combine uma condição LIKE com uma verificação STR_LENGTH.