Comment stocker une liste dans une colonne d'une table de base de données

donc, par réponse de Mehrdad à une question connexe , I get it qu'une colonne de table de base de données" correcte " ne stocke pas une liste. Plutôt, vous devez créer une autre table qui détient effectivement les éléments de ladite liste et puis la relier directement ou à travers une table de jonction. Cependant, le type de liste que je veux créer sera composé d'éléments uniques (contrairement à l'exemple fruit de la question liée). En outre, l' les éléments de ma liste sont explicitement Classés - ce qui signifie que si je stockais les éléments dans une autre table, je devrais les trier chaque fois que je les accédais. Enfin, la liste est essentiellement atomique en ce que chaque fois que je souhaite accéder à la liste, je veux accéder à l'ensemble de la liste plutôt que juste un morceau de celui - ci-il semble donc stupide de devoir émettre une requête de base de données pour rassembler des morceaux de la liste.

la solution D'AKX (liée ci-dessus) est de sérialiser la liste et de la stocker dans un colonne binaire. Mais cela semble aussi incommode parce que cela signifie que je dois m'inquiéter de la sérialisation et de la desérialisation.

y a-t-il une meilleure solution? Si n'est pas une meilleure solution, alors pourquoi? Il semble que ce problème doit venir de temps à autre.

... juste un peu plus d'infos pour vous dire d'où je viens. Dès que j'ai commencé à comprendre SQL et bases de données en général, j'ai été transformé sur LINQ à SQL, et donc maintenant je suis un peu gâté parce que je m'attends à traiter avec mon modèle d'objet de programmation sans avoir à penser à la façon dont les objets sont interrogés ou stockés dans la base de données.

Merci À Tous!

John

mise à jour: dans la première série de réponses que j'obtiens, je vois" vous pouvez suivre la route CSV/XML... mais NE le faites PAS!". Donc maintenant je cherche des explications sur pourquoi. M'indiquer quelques bonnes références.

aussi, pour vous donner une meilleure idée de ce que je fais: dans ma base de données,j'ai une table de fonctions qui aura une liste de paires (x, y). (Les membres de la table disposeront également d'autres renseignements qui n'ont aucune incidence sur notre discussion.) J'ai n'auront jamais besoin de voir une partie de la liste de (x,y) paires. Je vais plutôt les prendre tous et les dessiner à l'écran. Je vais permettre à l'utilisateur de faire glisser les nœuds autour pour modifier les valeurs à l'occasion ou ajouter plus de valeurs à l'intrigue.

80
demandé sur Community 2010-06-18 18:20:09

10 réponses

Non, il n'y a pas de "meilleure" façon de stocker une séquence d'éléments dans une seule colonne. Les bases de données relationnelles sont conçues spécifiquement pour stocker une valeur par combinaison ligne/colonne. Afin de stocker plus d'une valeur, vous doit sérialiser votre liste en une seule valeur pour le stockage, puis le désérialiser lors de la lecture. Il n'y a pas d'autre façon de faire ce dont vous parlez (parce que ce dont vous parlez est une mauvaise idée que ne devrait, en général, jamais être fait ).

je comprends que vous pensez qu'il est stupide de créer une autre table pour stocker cette liste, mais c'est exactement ce que font les bases de données relationnelles. Vous menez une bataille difficile et violez l'un des principes les plus fondamentaux de la conception de base de données relationnelles sans raison valable. Puisque vous déclarez que vous êtes en train D'apprendre SQL, je fortement vous conseiller d'éviter cette idée et de s'en tenir aux pratiques recommandé par des développeurs SQL plus expérimentés.

le principe que vous violez est appelé première forme normale , qui est la première étape dans la normalisation de base de données.

au risque de simplifier à l'excès les choses, la normalisation de base de données est le processus de définition de votre base de données basée sur ce que les données est , de sorte que vous pouvez écrire des requêtes sensées et cohérentes contre elle et être en mesure de la maintenir facilement. La normalisation est conçue pour limiter les incohérences logiques et la corruption dans vos données, et il ya beaucoup de niveaux à elle. L'article de Wikipedia sur normalisation de base de données est en fait assez bon.

fondamentalement, la première règle (ou forme) de normalisation stipule que votre table doit représenter une relation. Cela signifie que:

  • vous devez pouvoir différencier une rangée de toute autre rangée (en d'autres termes, vous table doit avoir quelque chose qui peut servir comme clé primaire. Cela signifie également qu'aucune ligne doit être dupliqué.
  • tout ordre des données doit être défini par les données, et non par l'ordre physique des lignes (SQL est basé sur l'idée d'un ensemble, ce qui signifie que le seulement l'ordre sur lequel vous devez compter est celui que vous définissez explicitement dans votre requête)
  • toute intersection d'une ligne ou d'une colonne doit: contiennent un et un seul valeur

Le dernier point est évidemment le point saillant ici. SQL est conçu pour stocker vos ensembles pour vous, pas pour vous fournir un" seau " pour vous de stocker un ensemble vous-même. Oui, il est possible de faire. Non, le monde ne finira pas. Vous avez, cependant, déjà estropié vous-même dans la compréhension de SQL et les meilleures pratiques qui vont avec elle en sautant immédiatement dans l'utilisation d'un ORM. LINQ to SQL is fantastique, tout comme les calculatrices graphiques sont. Dans le même ordre d'idées, cependant, ils devraient et non comme un substitut pour savoir comment les processus qu'ils emploient fonctionnent réellement.

Votre liste peut être entièrement "atomique" maintenant, et qui ne peuvent pas changer pour ce projet. Mais vous allez, cependant, prendre l'habitude de faire des choses similaires dans d'autres projets, et vous finirez (probablement rapidement) par tomber dans un scénario où vous êtes maintenant adapté à votre quick-n-easy l'approche fondée sur la liste en colonne lorsqu'elle est totalement inappropriée. Il n'y a pas beaucoup de travail supplémentaire dans la création de la table correcte pour ce que vous essayez de stocker, et vous ne serez pas tourné en ridicule par D'autres développeurs SQL quand ils verront votre conception de base de données. En outre, LINQ à SQL va voir votre relation et vous donner l'interface orientée objet appropriée à votre liste automatiquement . Pourquoi renonceriez-vous à la commodité offerte par L'ORM pour que vous puissiez effectuer des et mal avisée de la base de données hackery?

128
répondu Adam Robinson 2010-06-18 14:52:36

vous pouvez juste oublier SQL tous ensemble et aller avec une approche "NoSQL". RavenDB , MongoDB et CouchDB saut à l'esprit que les solutions possibles. Avec une approche NoSQL, vous n'utilisez pas le modèle relationnel..tu n'es même pas contraint aux schémas.

8
répondu jaltiere 2010-06-18 14:34:44

ce que j'ai vu beaucoup de gens faire est ceci (ce n'est peut-être pas la meilleure approche, corrigez-moi si je me trompe):

le tableau que j'utilise dans l'exemple est donné ci-dessous(le tableau inclut les Surnoms que vous avez donnés à vos amies spécifiques. Chaque petite amie a un id unique):

nicknames(id,seq_no,names)

Supposez, vous voulez stocker beaucoup de surnoms sous une carte d'identité. C'est pourquoi nous avons inclus un champ seq_no .

maintenant, remplissez ces valeurs à votre table:

(1,1,'sweetheart'), (1,2,'pumpkin'), (2,1,'cutie'), (2,2,'cherry pie')

si vous voulez trouver tous les noms que vous avez donnés à votre amie id 1, alors vous pouvez utiliser:

select names from nicknames where id = 1;
7
répondu H. Pauwelyn 2015-07-26 13:15:18

en plus de ce que tout le monde a dit, je vous suggérerais d'analyser votre approche à plus long terme que maintenant. Il est actuellement le cas que les articles sont uniques. Il est actuellement le cas où le recours aux éléments nécessiterait une nouvelle liste. Il est presque nécessaire que la liste soit actuellement courte. Même si je n'ai pas les détails du domaine, il n'est pas très difficile de penser que ces exigences pourraient changement. Si vous sérialisez votre liste, vous êtes en train de cuire dans une rigidité qui n'est pas nécessaire dans un design plus normalisé. Btw, cela ne signifie pas nécessairement un nombre plein:beaucoup de relations. Vous pouvez juste avoir une table enfant simple avec une clé étrangère au parent et une colonne de caractère pour l'article.

si vous voulez toujours suivre cette voie de sérialisation de la liste, vous pourriez envisager de stocker la liste en XML. Certaines bases de données telles que SQL Server ont même un type de données XML. La seule raison pour laquelle je suggère XML est que presque par définition, cette liste doit être courte. Si la liste est longue, alors la sérialiser en général est une approche terrible. Si vous empruntez la route CSV, vous devez tenir compte des valeurs contenant le délimiteur, ce qui signifie que vous êtes obligé d'utiliser des identificateurs Cités. En supposant que les listes sont courtes, il ne fera probablement pas beaucoup de différence si vous utilisez CSV ou XML.

3
répondu Thomas 2010-06-18 14:39:48

si vous avez besoin d'interroger sur la liste, alors stocker dans une table.

si vous voulez toujours la liste, vous pouvez la stocker comme une liste délimitée dans une colonne. Même dans ce cas, sauf si vous avez des raisons très spécifiques de ne pas, stocker dans une table de recherche.

2
répondu hometoast 2010-06-18 14:28:01

je le stockerais simplement comme CSV, si ce sont des valeurs simples, alors il devrait être tout ce dont vous avez besoin (XML est très verbeux et sérialiser à/à partir de cela serait probablement exagéré, mais ce serait une option aussi bien).

voici un bonne réponse pour savoir comment retirer CSVs avec LINQ.

1
répondu David Neale 2017-05-23 10:31:27

une seule option n'est pas mentionnée dans les réponses. Vous pouvez désormaliser votre conception de base de données. Si vous avez besoin de deux tables. Une table contient la liste appropriée, un article par ligne, une autre table contient la liste entière dans une colonne (séparée du coma, par exemple).

ici, il est "traditionnel" DB design:

List(ListID, ListName) 
Item(ItemID,ItemName) 
List_Item(ListID, ItemID, SortOrder)

ici, il est de-table normalisée:

Lists(ListID, ListContent)

l'idée ici - vous maintenez des listes table en utilisant des déclencheurs ou le code de l'application. Chaque fois que vous modifiez le contenu List_Item, les lignes appropriées dans les listes sont mises à jour automatiquement. Si vous lisez surtout des listes, ça pourrait très bien marcher. Avantages - vous pouvez lire les listes dans une déclaration. Les contre-mises à jour prennent plus de temps et d'efforts.

1
répondu Alsin 2010-06-18 15:07:53

si vous voulez vraiment le stocker dans une colonne et l'avoir queryable beaucoup de bases de données soutiennent XML maintenant. Si vous ne posez pas de questions, vous pouvez les stocker en tant que valeurs séparées par des virgules et les analyser avec une fonction lorsque vous avez besoin d'eux séparés. Je suis d'accord avec tout le monde bien que si vous cherchez à utiliser une base de données relationnelles une grande partie de la normalisation est la séparation des données comme cela. Je ne dis pas que toutes les données correspondent à une base de données relationnelle. Vous pouvez toujours regarder dans d'autres types de bases de données si les données ne correspondent pas au modèle.

0
répondu David Daniel 2010-06-30 14:42:07

je pense que dans certains cas, vous pouvez créer une fausse" liste " d'articles dans la base de données, par exemple, la marchandise a quelques photos pour montrer ses détails, vous pouvez concaténer tous les IDs de photos divisé par virgule et stocker la chaîne dans le DB, alors vous avez juste besoin de parser la chaîne quand vous en avez besoin. Je travaille maintenant sur un site web et j'ai l'intention de l'utiliser de cette façon.

0
répondu Nen 2016-10-18 16:40:20

réponse Simple: si, et seulement si, vous êtes certain que la liste sera toujours utilisée comme liste, alors rejoignez la liste ensemble de votre côté avec un caractère (tel que '\0') qui ne sera jamais utilisé dans le texte, et stockez-le. Ensuite, lorsque vous récupérez, vous pouvez diviser par '\0'. Il y a bien sûr d'autres façons de faire ce genre de choses, mais celles-ci dépendent de votre fournisseur de base de données spécifique.

par exemple, vous pouvez stocker JSON dans une base de données Postgres. Si votre liste est texte, et vous voulez juste la liste sans tracas, c'est un compromis raisonnable.

D'autres ont risqué des suggestions de sérialisation, mais je ne pense pas vraiment que la sérialisation est une bonne idée: une partie de la chose soignée au sujet des bases de données est que plusieurs programmes écrits dans des langues différentes peuvent parler les uns aux autres. Et les programmes sérialisés au format Java ne feraient pas tout si bien si un programme Lisp voulait les charger.

Si vous voulez un bonne façon de faire ce genre de chose, Il ya généralement des types array-ou-similaires disponibles. Postgres par exemple, offre tableau comme un type, et vous permet de stocker un tableau de texte, si c'est ce que vous voulez , et il y a des trucs similaires pour MySql et MS SQL 151980920 "en utilisant JSON, et IBM DB2 offrent un type de tableau ainsi (dans leur propre utile documentation). Ce ne serait pas si commun si il n'y avait pas besoin de cela.

ce que vous perdez en allant dans cette voie est la notion de la liste comme un tas de choses dans l'ordre. Au moins nominalement, les bases de données traitent les champs comme des valeurs uniques. Mais si c'est tout ce que tu veux, alors tu devrais foncer. C'est un jugement de valeur que tu dois faire pour toi-même.

0
répondu Haakon Løtveit 2017-05-25 09:50:10