2011-08-11 77 views
13

Así que mi pregunta es bastante simple:Cómo contar artículos en lista separada por comas de MySQL

tengo una columna en SQL que es una lista separada por comas (es decir cats,dogs,cows,) Necesito contar el número de elementos en ella usando única SQL (así que lo que mi función es (permite llamarlo fx por ahora) sería el siguiente:

SELECT fx(fooCommaDelimColumn) AS listCount FROM table WHERE id=... 

sé que es defectuoso, pero usted consigue la idea (por cierto, si el valor de fooCommaDelimColumn es cats,dogs,cows,, luego listCount debería devolver 4 ...).

Eso es todo.

+0

Este hilo ha sido contestada sobre [aquí] (https: // stackoverflow.com/preguntas/5033047/mysql-query-finding-valores-in-a-separada por comas-string/47069224 # 47069224) – Delickate

Respuesta

38

No hay ninguna función integrada que cuenta las ocurrencias de subcadena en una cadena, pero se puede calcular la diferencia entre la cadena original, y la misma cadena sin comas:

LENGTH(fooCommaDelimColumn) - LENGTH(REPLACE(fooCommaDelimColumn, ',', '')) 
+0

Aunque esto funciona, puede ser bueno para decir que Tomás no tendría este problema si tenía correctamente modelado es una base de datos. –

+6

En realidad se debe sumar 1 a la respuesta en caso de que haya sólo un elemento de la lista: longitud (fooCommaDelimColumn) - LONGITUD (SUSTITUIR (fooCommaDelimColumn, '', '')) + 1. Esto todavía merece un 1 para el principio expresado. – RolandoMySQLDBA

+0

@RolandoMySQLDBA: Pensé lo mismo, pero la cadena de Tomás incluía una coma al final, por lo que no es necesaria. –

6

zerkms' funciona, no hay duda al respecto. Pero su problema es creado por un esquema de base de datos incorrecto, como señaló Steve Wellens. No debe tener más de un valor en una columna porque rompe la primera ley normal. En cambio, debes hacer al menos dos tablas. Por ejemplo, digamos que usted tiene miembros que poseen animales:

table member (member_id, member_name) 
table member_animal (member_id, animal_name) 

Aún mejor: ya que muchos usuarios pueden tener el mismo tipo de animal, se debe crear 3 tablas:

table member (member_id, member_name) 
table animal (animal_id, animal_name) 
table member_animal (member_id, animal_id) 

Se podría llenar sus mesas de este tipo, por ejemplo:

member (1, 'Tomas') 
member (2, 'Vincent') 
animal (1, 'cat') 
animal (2, 'dog') 
animal (3, 'turtle') 
member_animal (1, 1) 
member_animal (1, 3) 
member_animal (2, 2) 
member_animal (2, 3) 

Y, para responder a su pregunta inicial, esto es lo que haría si usted quería saber cuántos animales cada usuario tiene:

SELECT member_id, COUNT(*) AS num_animals 
FROM member 
INNER JOIN member_animal 
    USING (member_id) 
INNER JOIN animal 
    USING (animal_id) 
GROUP BY member_id; 
+0

De hecho, esta respuesta es más * correcta *. Aquí, en por lo que estamos a ayudarse entre sí para implementar de una manera correcta, para resolver la raíz de los problemas, +1 – zerkms

+0

Gracias por la ayuda, yo todavía me gusta tener en mis manos algunos recursos de aprendizaje, aunque (como se puede ver mi conocimiento SQL termina con ACTUALIZACIÓN :)) – Tomas

4

Siguiendo la sugerencia de @zerkms.

Si usted no sabe si hay una coma final o no, utilizar la función Recortar para eliminar las comas finales:

(
    LENGTH(TRIM(BOTH ',' FROM fooCommaDelimColumn)) 
    - LENGTH(REPLACE(TRIM(BOTH ',' FROM fooCommaDelimColumn), ',', '')) 
    + 1 
) as count 

Referencia: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_trim

También coinciden en que una refactorización de las mesas es la mejor opción, pero si esto no es posible ahora, este fragmento puede hacer el trabajo.

+0

Esta es la solución completa. A veces se requiere almacenar datos (matriz) en forma codificada JSON (por ejemplo, '[" ABC "," DEF "," GHI "," JKL "]') y aún contar los elementos dentro. Para este propósito, su solución funciona incluso sin * recorte *. – shadyyx

2

Esta versión no es compatible con iniciales o finales comas, pero es compatible con un valor vacío con un recuento de 0:

IF(values, LENGTH(values) - LENGTH(REPLACE(values, ',', '')) + 1, 0) AS values_count 
Cuestiones relacionadas