Mysql
 sql >> Database >  >> RDS >> Mysql

Come utilizzare regexp sui risultati di una query secondaria?

Prova una di queste query:

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]+$'

o

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 il numero di "cifre finali" non è fisso, puoi anche utilizzare:

LIKE concat(u.phone_no, '%')

o

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

Ma in questo caso potresti dover usare SELECT DISTICT a.phone_no se è possibile che un users.phone_no è una sottosequenza di un altro users.phone_no (es. 99123 e 991234).

Aggiorna

Dopo aver eseguito alcuni test con 10.000 righe per la tabella degli utenti e 100.000 righe per la tabella di ammissione, sono arrivato alla seguente query:

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

In questo modo puoi usare REGEXP e avere ancora grandi prestazioni. Questa query viene eseguita quasi istantaneamente nel mio test case.

Logicamente hai solo bisogno delle condizioni REGEXP. Ma su tabelle più grandi la query potrebbe scadere. L'utilizzo di una condizione LIKE filtrerà il set di risultati prima del controllo REGEXP. Ma anche usando LIKE la query non funziona molto bene. Per qualche motivo MySQL non utilizza un controllo dell'intervallo per il join. Quindi ho aggiunto un controllo esplicito dell'intervallo:

    ON  a.phone_no >= u.phone_no
    AND a.phone_no < CONCAT(u.phone_no, 'z')

Con questo controllo puoi rimuovere la condizione LIKE dalla parte JOIN.

La parte UNION sostituisce DISTICT. MySQL sembra tradurre DISTINCT in un'istruzione GROUP BY, che non funziona bene. Usando UNION con un set di risultati vuoto, forzo MySQL a rimuovere i duplicati dopo SELECT. Puoi rimuovere quella riga, se utilizzi un numero fisso di cifre finali.

Puoi adattare i modelli REGEXP alle tue esigenze:

...
    AND a.phone_no REGEXP CONCAT('^', u.phone_no, '[0-9]{2}$')
...
    AND u.phone_no REGEXP  '^(99)+[0-9]{8}$'
...

Se hai solo bisogno di REGEXP per controllare la lunghezza di phone_no, puoi anche utilizzare una condizione LIKE con il segnaposto '_'.

    AND a.phone_no LIKE CONCAT(u.phone_no, '__')
...
    AND u.phone_no LIKE '99________$'

oppure combina una condizione LIKE con un controllo STR_LENGTH.