web-dev-qa-db-fra.com

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

Donc, pour réponse de Mehrdad à une question connexe , je l'obtenir qu'une colonne de table de base de données "appropriée" ne stocke pas de liste. Vous devez plutôt créer une autre table contenant effectivement les éléments de ladite liste, puis la lier directement ou par le biais d'une table de jonction. Cependant, le type de liste que je veux créer sera composé d'éléments uniques (contrairement à l'exemple de la question liée fruit). De plus, les éléments de ma liste sont explicitement triés - ce qui signifie que si je stockais les éléments dans une autre table, je devrais les trier à chaque fois que j'y accédais. Enfin, la liste est fondamentalement atomique dans la mesure où chaque fois que je souhaite accéder à la liste, je souhaite accéder à la liste complète plutôt qu’à une partie de celle-ci - il semble donc ridicule de devoir lancer une requête de base de données pour rassembler des éléments de la liste. la liste.

La solution AKX (lien ci-dessus) consiste à sérialiser la liste et à la stocker dans une colonne binaire. Mais cela semble également gênant, car cela signifie que je dois m'inquiéter de la sérialisation et de la désérialisation.

Y a-t-il une meilleure solution? Si est pas de meilleure solution, alors pourquoi? Il semble que ce problème devrait surgir de temps en temps.

... Juste un peu plus d'infos pour vous dire d'où je viens. Dès que je venais juste de commencer à comprendre le SQL et les bases de données en général, on m'a lancé sur LINQ to SQL, et maintenant je suis un peu gâté parce que je m'attends à traiter mon modèle d'objet de programmation sans avoir à penser à la manière dont les objets sont interrogés ou stockés dans la base de données.

Merci a tous!

John

MISE À JOUR: Donc, dans la première série de réponses que je reçois, je vois "vous pouvez choisir la route CSV/XML ... mais ne le faites pas!". Alors maintenant, je cherche des explications sur pourquoi. Indiquez-moi de 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). (Le tableau contiendra également d'autres informations qui n'auront aucune incidence sur notre discussion.) Je n'aurai jamais besoin de voir une partie de la liste des paires (x, y). Je vais plutôt les prendre tous et les tracer à l'écran. Je permettrai à l'utilisateur de faire glisser les nœuds pour modifier les valeurs de temps en temps ou d'ajouter d'autres valeurs au tracé.

96
JnBrymn

Non, il n'y a pas de "meilleur" moyen 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 devez sérialisez votre liste en une valeur unique pour le stockage, puis désérialisez-la lors de l'extraction. Il n'y a pas d'autre moyen de faire ce dont vous parlez (parce que ce dont vous parlez est une mauvaise idée qui devrait, en général, ne jamais être réalisée).

Si j'ai bien compris, vous pensez qu'il est ridicule 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 enfreignez l'un des principes les plus fondamentaux de la conception de bases de données relationnelles sans raison valable. Puisque vous dites que vous venez d’apprendre le SQL, je vous conseillerais vivement d’éviter cette idée et de vous en tenir aux pratiques recommandées par SQL plus expérimenté. développeurs.

Le principe que vous violez s'appelle première forme normale, qui constitue la première étape de la normalisation de la base de données.

Au risque de simplifier excessivement les choses, la normalisation de la base de données est le processus de définition de votre base de données en fonction de ce que les données est, afin que vous puissiez écrire des requêtes cohérentes et sensibles contre elle et pouvoir le conserver facilement. . La normalisation est conçue pour limiter les incohérences logiques et la corruption dans vos données, et comporte de nombreux niveaux. L'article de Wikipedia sur normalisation de la base de données est en fait plutôt 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 être capable de différencier une ligne d'une autre (en d'autres termes, votre table doit avoir quelque chose qui peut servir de clé primaire. Cela signifie également qu'aucune ligne ne doit être dupliquée.
  • 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 l’ordre seulement sur lequel vous devez vous appuyer est celui que vous définissez explicitement dans votre requête)
  • Chaque intersection ligne/colonne doit contenir un et un seul valeur

Le dernier point est évidemment le point saillant ici. SQL est conçu pour stocker vos jeux pour vous et non pour vous fournir un "seau" pour vous permettre de stocker un jeu vous-même. Oui, c'est possible. Non, le monde ne finira pas. Cependant, vous vous êtes déjà démoralisé dans la compréhension de SQL et des meilleures pratiques qui y sont associées en passant immédiatement à l’utilisation d’un ORM. LINQ to SQL est fantastique, tout comme les calculatrices graphiques. Dans le même ordre d'idées, cependant, ils devraient pas être utilisés comme substituts pour savoir comment les processus qu'ils utilisent fonctionnent réellement.

Votre liste peut être entièrement "atomique" maintenant, et cela ne changera peut-être pas pour ce projet. Cependant, vous prendrez l'habitude de faire la même chose dans d'autres projets et vous rencontrerez (probablement rapidement) un scénario dans lequel vous ajusterez maintenant votre liste rapide dans la colonne. approche où il est tout à fait inapproprié. Il n’ya pas beaucoup de travail supplémentaire à faire pour créer la table correcte pour ce que vous essayez de stocker, et les autres développeurs SQL ne se moqueront pas quand ils verront la conception de votre base de données. En outre, LINQ to SQL va voir votre relation et vous donner l'interface appropriée orientée objet de votre liste automatiquement. Pourquoi voudriez-vous abandonner la commodité offerte par l'ORM pour pouvoir effectuer un piratage de base de données non standard et peu judicieux?

158
Adam Robinson

Vous pouvez simplement oublier SQL et utiliser une approche "NoSQL". RavenDB , MongoDB et CouchDB sautent à l'esprit en tant que solutions possibles. Avec une approche NoSQL, vous n'utilisez pas le modèle relationnel. Vous n'êtes même pas contraint aux schémas.

13
jaltiere

Voici ce que j'ai vu beaucoup de gens faire (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 comprend les surnoms que vous avez donnés à vos petites amies spécifiques. Chaque petite amie a un identifiant unique):

nicknames(id,seq_no,names)

Supposons que vous souhaitiez stocker plusieurs pseudonymes sous un identifiant. C'est pourquoi nous avons inclus un seq_no champ.

Maintenant, remplissez ces valeurs dans votre tableau:

(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 à l'identifiant 1 de votre petite amie, vous pouvez utiliser:

select names from nicknames where id = 1;
8
user5157248

En plus de ce que tout le monde a dit, je vous suggérerais d'analyser votre approche plus à long terme que maintenant. C'est actuellement le cas où les éléments sont uniques. C'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 exagéré de penser que ces exigences pourraient changer. Si vous sérialisez votre liste, vous créez une rigidité qui n'est pas nécessaire dans une conception plus normalisée. Btw, cela ne signifie pas nécessairement une relation complète Many: Many. Vous pouvez simplement avoir une seule table enfant avec une clé étrangère pour le parent et une colonne de caractères pour l'élément.

Si vous souhaitez toujours suivre cette voie de sérialisation de la liste, vous pouvez envisager de stocker la liste au format 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érerais XML est que, presque par définition, cette liste doit être courte. Si la liste est longue, la sérialisation de celle-ci est en général une approche déplorable. Si vous choisissez la route CSV, vous devez prendre en compte les valeurs contenant le délimiteur, ce qui signifie que vous devez utiliser des identificateurs entre guillemets. En supposant que les listes soient courtes, le fait que vous utilisiez CSV ou XML ne fera probablement pas grande différence.

3
Thomas

Réponse simple: Si, et seulement si, vous êtes certain que la liste sera toujours utilisée comme liste, joignez-la à votre liste avec un caractère (tel que '\ 0') qui ne sera pas utilisé dans la liste. texte jamais, et stocker que. Ensuite, lorsque vous le récupérerez, vous pourrez vous séparer par '\ 0'. Il existe bien sûr d'autres façons de procéder, 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 contient du texte et que vous voulez simplement la liste sans autre problème, c'est un compromis raisonnable.

D'autres ont osé faire des suggestions de sérialisation, mais je ne pense pas vraiment que la sérialisation soit une bonne idée: ce qui est bien dans les bases de données, c'est que plusieurs programmes écrits dans différentes langues peuvent communiquer entre eux. Et les programmes sérialisés au format Java ne feraient pas très bien si un programme LISP voulait le charger.

Si vous voulez un bon moyen de faire ce genre de chose, il existe généralement des types de type tableau ou similaire. Postgres, par exemple, offre un tableau sous forme de type et vous permet de stocker un tableau de texte, si c'est ce que vous voulez , et il existe des astuces similaires pour MySql et MS SQL utilisant JSON et IBM DB2 offrent également un type de tableau (dans leur propre documentation utile ) . Cela ne serait pas si courant si cela n'était pas nécessaire.

Ce que vous perdez en allant dans cette voie, c’est la notion de liste comme un ensemble de choses en séquence. Au moins nominalement, les bases de données traitent les champs comme des valeurs uniques. Mais si c'est tout ce que vous voulez, alors vous devriez y aller. C'est un jugement de valeur que vous devez faire vous-même.

2
Haakon Løtveit

Si vous devez interroger la liste, stockez-la dans une table.

Si vous voulez toujours la liste, vous pouvez la stocker sous forme de liste délimitée dans une colonne. Même dans ce cas, stockez-le dans une table de recherche, sauf si vous avez des raisons TRÈS spécifiques.

2
hometoast

Une seule option n'est pas mentionnée dans les réponses. Vous pouvez dénormaliser votre conception de base de données. Donc, vous avez besoin de deux tables. Une table contient la liste appropriée, un élément par ligne, une autre table contient la liste complète dans une colonne (séparés par des virgules, par exemple).

Ici c'est la conception 'traditionnelle' de la base de données:

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

Ici c'est un tableau dé-normalisé:

Lists(ListID, ListContent)

L'idée ici - vous maintenez la table Lists en utilisant des déclencheurs ou du code d'application. Chaque fois que vous modifiez le contenu List_Item, les lignes appropriées des listes sont mises à jour automatiquement. Si vous lisez surtout des listes, cela pourrait fonctionner assez bien. Pros - vous pouvez lire les listes en une seule déclaration. Inconvénients - les mises à jour prennent plus de temps et d'efforts.

1
Alsin

Je le stockerais simplement au format CSV, si ce sont des valeurs simples, il ne devrait contenir que ce dont vous avez besoin (XML est très détaillé et la sérialisation de/vers ce serait probablement une perte de temps, mais ce serait également une option).

Voici un bonne réponse pour savoir comment extraire des CSV avec LINQ.

1
David Neale

Je pense que dans certains cas, vous pouvez créer une "liste" FAUX d'éléments dans la base de données. Par exemple, la marchandise contient quelques images pour afficher ses détails, vous pouvez concaténer tous les ID des images divisées par virgule et stocker la chaîne dans DB, vous avez juste besoin d’analyser la chaîne lorsque vous en avez besoin. Je travaille actuellement sur un site Web et je prévois de l'utiliser de cette façon.

0
Nen

Si vous voulez vraiment le stocker dans une colonne et le rendre interrogeable, de nombreuses bases de données prennent en charge XML maintenant. Si vous n'interrogez pas, vous pouvez les stocker en tant que valeurs séparées par des virgules et les analyser avec une fonction lorsque vous souhaitez les séparer. Je suis d’accord avec tout le monde, mais si vous envisagez d’utiliser une base de données relationnelle, la séparation des données de ce type est un aspect essentiel de la normalisation. Je ne dis pas que toutes les données correspondent à une base de données relationnelle. Vous pouvez toujours rechercher d'autres types de bases de données si bon nombre de vos données ne correspondent pas au modèle.

0
David Daniel