Comment compter le nombre d'occurrences d'une sous-chaîne dans une chaîne dans PostgreSQL?
Exemple:
J'ai une table
CREATE TABLE test."user"
(
uid integer NOT NULL,
name text,
result integer,
CONSTRAINT pkey PRIMARY KEY (uid)
)
Je souhaite écrire une requête afin que la variable result
contienne le nombre d'occurrences de la sous-chaîne o
que la colonne name
contient. Par exemple, si dans une ligne, name
est hello world
, la colonne result
doit contenir 2
, car il y a deux o
dans la chaîne hello world
.
En d'autres termes, j'essaie d'écrire une requête qui prendrait en entrée:
et mettez à jour la colonne result
:
Je connais la fonction regexp_matches
et son option g
, qui indique que la chaîne complète (g
= globale) doit être analysée pour rechercher la présence de toutes les occurrences de la sous-chaîne).
Exemple:
SELECT * FROM regexp_matches('hello world', 'o', 'g');
résultats
{o}
{o}
et
SELECT COUNT(*) FROM regexp_matches('hello world', 'o', 'g');
résultats
2
Mais je ne vois pas comment écrire une requête UPDATE
qui mettrait à jour la colonne result
de telle sorte qu'elle contienne le nombre d'occurrences de la sous-chaîne de la colonne name
.
Une solution commune repose sur cette logique: remplace la chaîne de recherche par une chaîne vide et divise la différence entre ancienne et nouvelle longueur par la longueur de la chaîne de recherche
(CHAR_LENGTH(name) - CHAR_LENGTH(REPLACE(name, 'substring', '')))
/ CHAR_LENGTH('substring')
Par conséquent:
UPDATE test."user"
SET result =
(CHAR_LENGTH(name) - CHAR_LENGTH(REPLACE(name, 'o', '')))
/ CHAR_LENGTH('o');
Une manière de faire Postgres'y convertit la chaîne en tableau et compte la longueur du tableau (puis soustrait 1):
select array_length(string_to_array(name, 'o'), 1) - 1
Notez que cela fonctionne également avec des sous-chaînes plus longues.
Par conséquent:
update test."user"
set result = array_length(string_to_array(name, 'o'), 1) - 1;
Occcurence_Count = LENGTH (REPLACE (string_to_search, string_to_find, '~')) - LENGTH (REPLACE (string_to_search, string_to_find, ''))
Cette solution est un peu plus propre que beaucoup d’autres que j’ai déjà vu, en particulier sans diviseur ..___. Vous pouvez en faire une fonction ou l’utiliser dans une sélection.
Aucune variable requise . J'utilise tilde comme caractère de remplacement, mais tout caractère ne figurant pas dans l'ensemble de données fonctionnera.
Autre moyen:
UPDATE test."user" SET result = length(regexp_replace(name, '[^o]', '', 'g'));