una - restricciones base de datos sql
Cómo almacenar una lista en una columna de una tabla de base de datos (10)
Además de lo que han dicho todos los demás, sugiero que analicen su enfoque en términos más largos que los que acabo de mencionar. Actualmente es el caso de que los artículos son únicos. Actualmente es el caso que recurrir a los artículos requeriría una nueva lista. Casi se requiere que la lista sea actualmente corta. Aunque no tengo los detalles del dominio, no es demasiado difícil pensar que esos requisitos podrían cambiar. Si serializas tu lista, estás horneando en una inflexibilidad que no es necesaria en un diseño más normalizado. Por cierto, eso no significa necesariamente una relación completa de Muchos: Muchos. Solo podría tener una única tabla secundaria con una clave externa para el elemento primario y una columna de caracteres para el elemento.
Si aún desea seguir este camino de serialización de la lista, puede considerar almacenar la lista en XML. Algunas bases de datos como SQL Server incluso tienen un tipo de datos XML. La única razón por la que sugeriría XML es que, casi por definición, esta lista debe ser breve. Si la lista es larga, serializarla en general es un enfoque horrible. Si utiliza la ruta CSV, debe contabilizar los valores que contienen el delimitador, lo que significa que está obligado a utilizar identificadores entrecomillados. Persuadido de que las listas son cortas, probablemente no hará mucha diferencia si usas CSV o XML.
Entonces, según la respuesta de Mehrdad a una pregunta relacionada , entiendo que una columna de tabla de base de datos "adecuada" no almacena una lista. Por el contrario, debe crear otra tabla que contenga efectivamente los elementos de dicha lista y luego vincularla directamente o a través de una tabla de unión. Sin embargo, el tipo de lista que deseo crear estará compuesto de elementos únicos (a diferencia del ejemplo de fruta de la pregunta vinculada). Además, los elementos de mi lista están ordenados explícitamente, lo que significa que si almacenara los elementos en otra tabla, tendría que ordenarlos cada vez que los accediera. Finalmente, la lista es básicamente atómica en el sentido de que cada vez que deseo acceder a la lista, querré acceder a toda la lista en lugar de solo una parte, por lo que me parece tonto tener que emitir una consulta de base de datos para reunir piezas de la lista.
La solución de AKX (vinculada anteriormente) consiste en serializar la lista y almacenarla en una columna binaria. Pero esto también parece inconveniente porque significa que tengo que preocuparme por la serialización y la deserialización.
¿Hay alguna solución mejor? Si no hay una mejor solución, ¿por qué? Parece que este problema debería aparecer de vez en cuando.
... solo un poco más de información para que sepa de dónde vengo. Tan pronto como comencé a entender el SQL y las bases de datos en general, me enfocaron en LINQ to SQL, y ahora estoy un poco mal porque espero lidiar con mi modelo de objetos de programación sin tener que pensar cómo los objetos son consultados o almacenados en la base de datos.
¡Gracias a todos!
John
ACTUALIZACIÓN: Entonces, en la primera ráfaga de respuestas que recibo, veo "puedes ir a la ruta CSV / XML ... ¡pero NO!". Así que ahora estoy buscando explicaciones de por qué. Señalarme algunas buenas referencias.
Además, para darle una mejor idea de lo que estoy haciendo: en mi base de datos tengo una tabla de funciones que tendrá una lista de pares (x, y). (La tabla también tendrá otra información que no tiene importancia para nuestra discusión). Nunca necesitaré ver parte de la lista de (x, y) pares. Por el contrario, los tomaré a todos y los representaré en la pantalla. Permitiré al usuario arrastrar los nodos para cambiar los valores ocasionalmente o agregar más valores a la gráfica.
Creo que en ciertos casos, puede crear una "lista" FALSA de elementos en la base de datos, por ejemplo, la mercancía tiene algunas imágenes para mostrar sus detalles, puede concatenar todas las ID de las imágenes divididas por comas y almacenar la cadena en el DB, entonces solo necesita analizar la cadena cuando la necesite. Estoy trabajando en un sitio web ahora y estoy planeando usarlo de esta manera.
Lo que he visto que muchas personas hacen es esto (puede que no sea el mejor enfoque, corríjanme si estoy equivocado):
La tabla que estoy usando en el ejemplo se muestra a continuación (la tabla incluye apodos que le ha dado a sus novias específicas. Cada novia tiene una identificación única):
nicknames(id,seq_no,names)
Supongamos que desea almacenar muchos apodos bajo una identificación. Es por eso que hemos incluido un campo seq_no
.
Ahora, llena estos valores a tu mesa:
(1,1,''sweetheart''), (1,2,''pumpkin''), (2,1,''cutie''), (2,2,''cherry pie'')
Si quieres encontrar todos los nombres que le has dado a tu id 1 de amiga, puedes usar:
select names from nicknames where id = 1;
No, no hay una "mejor" forma de almacenar una secuencia de elementos en una sola columna. Las bases de datos relacionales están diseñadas específicamente para almacenar un valor por combinación de fila / columna. Para almacenar más de un valor, debe serializar su lista en un único valor para su almacenamiento, luego deserializarla en la recuperación. No hay otra manera de hacer lo que estás diciendo (porque de lo que estás hablando es una mala idea que, en general, nunca debería hacerse ).
Entiendo que pienses que es una tontería crear otra tabla para almacenar esa lista, pero esto es exactamente lo que hacen las bases de datos relacionales. Estás librando una batalla cuesta arriba y violando uno de los principios más básicos del diseño de bases de datos relacionales sin una buena razón. Como usted declara que solo está aprendiendo SQL, le aconsejaría encarecidamente que evite esta idea y se adhiera a las prácticas recomendadas por los desarrolladores de SQL más experimentados.
El principio que estás violando se llama primera forma normal , que es el primer paso en la normalización de la base de datos.
A riesgo de simplificar demasiado las cosas, la normalización de la base de datos es el proceso de definición de su base de datos en función de los datos, de modo que pueda escribir consultas razonables y consistentes en su contra y poder mantenerla fácilmente. La normalización está diseñada para limitar las inconsistencias lógicas y la corrupción en sus datos, y hay muchos niveles para ella. El artículo de Wikipedia sobre la normalización de la base de datos en realidad es bastante bueno.
Básicamente, la primera regla (o forma) de normalización establece que su tabla debe representar una relación. Esto significa que:
- Debe poder diferenciar una fila de cualquier otra fila (en otras palabras, la tabla debe tener algo que pueda servir como clave principal. Esto también significa que no se debe duplicar ninguna fila).
- Cualquier orden de los datos debe definirse por los datos, no por el orden físico de las filas (SQL se basa en la idea de un conjunto, lo que significa que el único orden en el que debe confiar es el que defina explícitamente en su consulta)
- Cada intersección de fila / columna debe contener un solo valor
El último punto es obviamente el punto más destacado aquí. SQL está diseñado para almacenar sus conjuntos por usted, no para proporcionarle un "cubo" para que usted mismo almacene un conjunto. Sí, es posible hacer No, el mundo no terminará. Sin embargo, usted ya se ha paralizado al comprender SQL y las mejores prácticas que lo acompañan al saltar de inmediato al uso de un ORM. LINQ to SQL es fantástico, al igual que las calculadoras gráficas. En la misma línea, sin embargo, no deberían utilizarse como un sustituto para saber cómo funcionan realmente los procesos que emplean.
Su lista puede ser completamente "atómica" ahora, y eso puede no cambiar para este proyecto. Pero, sin embargo, tendrá el hábito de hacer cosas similares en otros proyectos, y eventualmente (probablemente rápidamente) se encontrará con un escenario en el que ahora está ajustando su lista rápida en n-fácil en una columna enfoque donde es totalmente inapropiado. No hay mucho trabajo adicional en la creación de la tabla correcta para lo que está tratando de almacenar, y no será ridiculizado por otros desarrolladores de SQL cuando vean el diseño de su base de datos. Además, LINQ to SQL verá su relación y le dará la interfaz adecuada orientada a objetos a su lista automáticamente . ¿Por qué renunciar a la comodidad que le ofrece el ORM para que pueda realizar una piratería de bases de datos no estándar y desaconsejable?
Respuesta simple: si, y solo si, está seguro de que la lista siempre se usará como una lista, entonces únase a la lista al final con un carácter (como ''/ 0'') que no se usará en el texto nunca, y almacenar eso. Luego, cuando lo recupere, puede dividir por ''/ 0''. Por supuesto, existen otras formas de abordar esto, pero eso depende de su proveedor de base de datos específico.
Como ejemplo, puede almacenar JSON en una base de datos de Postgres. Si su lista es de texto, y solo quiere la lista sin más problemas, ese es un compromiso razonable.
Otros han aventurado sugerencias de serialización, pero realmente no creo que la serialización sea una buena idea: parte de lo bueno de las bases de datos es que varios programas escritos en diferentes idiomas pueden comunicarse entre sí. Y los programas serializados usando el formato de Java no funcionarían tan bien si un programa Lisp quisiera cargarlo.
Si desea una buena forma de hacer este tipo de cosas, generalmente hay disponibles tipos de matriz o similar. Postgres, por ejemplo, ofrece una matriz como tipo, y le permite almacenar una matriz de texto, si eso es lo que desea , y hay trucos similares para MySql y MS SQL utilizando JSON, y DB2 de IBM también ofrece una matriz (en su propia documentación útil ). Esto no sería tan común si no fuera necesario.
Lo que se pierde yendo por ese camino es la noción de la lista como un montón de cosas en secuencia. Al menos nominalmente, las bases de datos tratan los campos como valores únicos. Pero si eso es todo lo que quieres, entonces debes hacerlo. Es un juicio de valor que tienes que hacer por ti mismo.
Si necesita consultar en la lista, guárdelo en una tabla.
Si siempre quiere la lista, puede almacenarla como una lista delimitada en una columna. Incluso en este caso, a menos que tenga razones MUY específicas para no hacerlo, guárdelo en una tabla de búsqueda.
Si realmente desea almacenarlo en una columna y hacer que se pueda consultar, muchas bases de datos admiten XML ahora. Si no está consultando, puede almacenarlos como valores separados por comas y analizarlos con una función cuando los necesite separados. Estoy de acuerdo con todos los demás, aunque si buscas utilizar una base de datos relacional, una gran parte de la normalización es la separación de datos como ese. Sin embargo, no estoy diciendo que todos los datos se ajusten a una base de datos relacional. Siempre puede buscar en otros tipos de bases de datos si muchos de sus datos no se ajustan al modelo.
Solo lo almacenaba como CSV, si son valores simples, entonces debería ser todo lo que necesita (XML es muy detallado y serializar desde / hacia él probablemente sería exagerado, pero eso sería una opción también).
Aquí hay una buena respuesta sobre cómo extraer CSV con LINQ.
Solo una opción no se menciona en las respuestas. Puede desnormalizar su diseño de base de datos. Entonces necesitas dos tablas. Una tabla contiene la lista adecuada, un elemento por fila, otra tabla contiene una lista completa en una columna (coma-separado, por ejemplo).
Aquí está el diseño de DB ''tradicional'':
List(ListID, ListName)
Item(ItemID,ItemName)
List_Item(ListID, ItemID, SortOrder)
Aquí está la tabla desnormalizada:
Lists(ListID, ListContent)
La idea aquí: mantienes la tabla de Listas usando disparadores o código de aplicación. Cada vez que modifique el contenido de List_Item, las filas apropiadas en Lists se actualizarán automáticamente. Si lees principalmente listas, podría funcionar bastante bien. Pros: puedes leer listas en una sola declaración. Contras: las actualizaciones requieren más tiempo y esfuerzos.