2016-04-02 19 views
18

Come posso contare il numero di occorrenze di una sottostringa all'interno di una stringa in PostgreSQL?Contare il numero di occorrenze di una sottostringa all'interno di una stringa in PostgreSQL


Esempio:

Ho una tabella

CREATE TABLE test."user" 
(
    uid integer NOT NULL, 
    name text, 
    result integer, 
    CONSTRAINT pkey PRIMARY KEY (uid) 
) 

Voglio scrivere una query in modo che la colonna di result contiene il numero di occorrenze della stringa o colonna name contiene. Ad esempio, se in una riga, name è hello world, la colonna result deve contenere 2, poiché nella stringa hello world sono presenti due numeri .

In altre parole, io sto cercando di scrivere una query che avrebbe preso come input:

enter image description here

e aggiornare la colonna result:

enter image description here


I sono a conoscenza della funzione regexp_matches e della sua opzione g, che indica che la stringa completa (g = global) deve essere sottoposta a scansione per la presenza di tutte le occorrenze della sottostringa).

Esempio:

SELECT * FROM regexp_matches('hello world', 'o', 'g'); 

rendimenti

{o} 
{o} 

e

SELECT COUNT(*) FROM regexp_matches('hello world', 'o', 'g'); 

restituisce

2 

Ma non vedo come scrivere una query result che aggiorni la colonna result in modo da contenere il numero di occorrenze della sottostringa o della colonna name.

+0

Possibile duplicato del [PostgreSQL numero di conteggio delle volte si verifica stringa nel testo] (http://stackoverflow.com/questions/25757194/postgresql -count-number-of-times-substring-happens-in-text) –

risposta

21

Una soluzione comune è basato su questa logica: sostituire la stringa di ricerca con una stringa vuota e dividere la differenza tra vecchio e nuovo lunghezza per la lunghezza della stringa di ricerca

(CHAR_LENGTH(name) - CHAR_LENGTH(REPLACE(name, 'substring', ''))) 
/CHAR_LENGTH('substring') 

Quindi:

UPDATE test."user" 
SET result = 
    (CHAR_LENGTH(name) - CHAR_LENGTH(REPLACE(name, 'o', ''))) 
    /CHAR_LENGTH('o'); 
+0

Questa è una risposta solida, ed è giusta. Potresti essere interessato al mio articolo [tutti i metodi per farlo] (http://dba.stackexchange.com/a/166763/2639) –

+0

Grazie! Qualcuno sa, perché non esiste un modo più semplice? Voglio dire, REPLACE già passa attraverso il problema di scansionare l'intera stringa per tutte le occorrenze, perché non avere qualcosa che faccia la metà del lavoro di REPLACE - conta solo le occorrenze –

+0

@AleksandrLevchuk: Beh, puoi scrivere la tua funzione definita dall'utente facendo questo calcolo, ad es c'è "REGEXP_COUNT" di Oracle in https://www.enterprisedb.com/docs/en/9.5/eeguide/EDB_Postgres_Enterprise_Guide.1.041.html. – dnoeth

13

un Postgres'y modo per farlo converte la stringa in un array e conta la lunghezza della matrice (e quindi sottrae 1):

select array_length(string_to_array(name, 'o'), 1) - 1 

Si noti che questo funziona anche con sottostringhe più lunghe.

qui:

update test."user" 
    set result = array_length(string_to_array(name, 'o'), 1) - 1; 
+2

Se qualcuno ha bisogno di regexp, anche questa soluzione con "regexp_split_to_array" invece di "string_to_array" funziona. –

+0

Questa soluzione è sostanzialmente più lenta del suggerimento di @ dnoeth. Non penso che sia di più: Postgres-y. Quando le cose sono più veloci e più portabili con un metodo diverso, penso che lo chiamiamo * meglio *. =) –

+1

@EvanCarroll Sfortunatamente, la risposta di dnoeth non funzionerà per le partite regolari, dal momento che potresti non sapere la durata della partita. Questa risposta funzionerà sia per le partite regolari che per le partite di stringhe raw. Penso che ciò che chiamiamo _ meglio_ è la soluzione che funziona per tutto ciò che stai cercando di fare :) – WebWanderer

0

Altro modo:

UPDATE test."user" SET result = length(regexp_replace(name, '[^o]', '', 'g')); 
Problemi correlati