Agrupación difusa en Postgres
-
22-07-2019 - |
Pregunta
Tengo una tabla con contenido similar a este:
id | title
------------
1 | 5. foo
2 | 5.foo
3 | 5. foo*
4 | bar
5 | bar*
6 | baz
6 | BAZ
& # 8230; y así sucesivamente. Me gustaría agrupar por títulos e ignorar los bits adicionales. Sé que Postgres puede hacer esto:
SELECT * FROM (
SELECT regexp_replace(title, '[*.]+
Sin embargo, eso es bastante simple y se volvería muy difícil de manejar si intentara anticipar todas las variaciones posibles. Entonces, la pregunta es, ¿hay una forma más general de hacer agrupación difusa que usar regexp? ¿Es posible, al menos sin romper la espalda para hacerlo?
Editar: para aclarar, no hay preferencia por ninguna de las variaciones, y así es como debería verse la tabla después de la agrupación:
title
------
5. foo
bar
baz
Es decir, las variaciones serían elementos que son diferentes solo por unos pocos caracteres o mayúsculas, y no importa cuáles quedan mientras estén agrupados.
, '') AS title
FROM table
) AS a
GROUP BY title
Sin embargo, eso es bastante simple y se volvería muy difícil de manejar si intentara anticipar todas las variaciones posibles. Entonces, la pregunta es, ¿hay una forma más general de hacer agrupación difusa que usar regexp? ¿Es posible, al menos sin romper la espalda para hacerlo?
Editar: para aclarar, no hay preferencia por ninguna de las variaciones, y así es como debería verse la tabla después de la agrupación:
<*>Es decir, las variaciones serían elementos que son diferentes solo por unos pocos caracteres o mayúsculas, y no importa cuáles quedan mientras estén agrupados.
Solución
Para cualquier agrupación debe tener igualdad transitiva, es decir a ~ = b, b ~ = c = > a ~ = c
.
Formúlelo estrictamente usando palabras e intentaremos formularlo usando SQL
.
Por ejemplo, ¿a qué grupo debe ir foo * bar
?
Update:
Esta consulta reemplaza todos los caracteres no alfanuméricos con espacios y devuelve el primer título de cada grupo:
SELECT DISTINCT ON (REGEXP_REPLACE(UPPER(title), '[^[:alnum:]]', '', 'g')) title
FROM (
VALUES
(1, '5. foo'),
(2, '5.foo'),
(3, '5. foo*'),
(4, 'bar'),
(5, 'bar*'),
(6, 'baz'),
(7, 'BAZ')
) rows (id, title)
Otros consejos
En algún momento, tendrá que definir qué hace que un conjunto de valores pertenezca a un grupo. Si eso es demasiado difícil, tal vez debería prohibir e inhibir la entrada de datos confusos, o si debe permitirlo, agregue una columna que contenga una versión desinfectada del título para que la utilicen las operaciones de agrupación.