web-dev-qa-db-fra.com

Liste liée en SQL

Quelle est la meilleure façon de stocker une liste chaînée dans une base de données mysql afin que les insertions soient simples (c'est-à-dire que vous n'avez pas à réindexer un tas de choses à chaque fois) et que la liste puisse être facilement extraite dans l'ordre.

57
magicrobotmonkey

Stockez une colonne entière dans votre table appelée "position". Enregistrez un 0 pour le premier élément de votre liste, un 1 pour le deuxième élément, etc. Indexez cette colonne dans votre base de données, et lorsque vous souhaitez extraire vos valeurs, triez par cette colonne.

 alter table linked_list add column position integer not null default 0;
 alter table linked_list add index position_index (position);
 select * from linked_list order by position;

Pour insérer une valeur à l'index 3, modifiez les positions des lignes 3 et supérieures, puis insérez:

 update linked_list set position = position + 1 where position >= 3;
 insert into linked_list (my_value, position) values ("new value", 3); 
16
Adrian Dunston

En utilisant la solution d'Adrian, mais au lieu d'incrémenter de 1, incrémentez de 10 ou même de 100. Ensuite, les insertions peuvent être calculées à la moitié de la différence de ce que vous insérez entre sans avoir à tout mettre à jour sous l'insertion. Choisissez un nombre suffisamment grand pour gérer votre nombre moyen d'insertions - s'il est trop petit, vous devrez revenir à la mise à jour de toutes les lignes avec une position plus élevée lors d'une insertion.

17
cfeduke

créer une table avec deux colonnes auto-référencées PreviousID et NextID. Si l'élément est la première chose dans la liste, PreviousID sera nul, s'il est le dernier, NextID sera nul. Le SQL ressemblera à ceci:

create table tblDummy
{
     PKColumn     int     not null, 
     PreviousID     int     null, 
     DataColumn1     varchar(50)     not null, 
     DataColumn2     varchar(50)     not null,  
     DataColumn3     varchar(50)     not null, 
     DataColumn4     varchar(50)     not null, 
     DataColumn5     varchar(50)     not null, 
     DataColumn6     varchar(50)     not null, 
     DataColumn7     varchar(50)     not null, 
     NextID     int     null
}
15
B0fh

Une liste chaînée peut être stockée à l'aide de pointeurs récursifs dans le tableau. C'est à peu près les mêmes hiérarchies sont stockées dans Sql et cela utilise le modèle d'association récursive.

Vous pouvez en savoir plus ici .

J'espère que ça aide.

4
user9252

L'option la plus simple serait de créer un tableau avec une ligne par élément de liste, une colonne pour la position de l'élément et des colonnes pour les autres données de l'élément. Ensuite, vous pouvez utiliser ORDER BY sur la colonne de position pour récupérer dans l'ordre souhaité.

create table linked_list
(   list_id   integer not null
,   position  integer not null 
,   data      varchar(100) not null
);
alter table linked_list add primary key ( list_id, position );

Pour manipuler la liste, il suffit de mettre à jour la position, puis d'insérer/supprimer des enregistrements si nécessaire. Donc, pour insérer un élément dans la liste 1 à l'index 3:

begin transaction;

update linked_list set position = position + 1 where position >= 3 and list_id = 1;

insert into linked_list (list_id, position, data)
values (1, 3, "some data");

commit;

Étant donné que les opérations sur la liste peuvent nécessiter plusieurs commandes (par exemple, une insertion nécessitera un INSERT et une MISE À JOUR), assurez-vous de toujours exécuter les commandes dans une transaction.

Une variante de cette option simple consiste à incrémenter la position d'un facteur pour chaque élément, par exemple 100, de sorte que lorsque vous effectuez un INSERT, vous n'avez pas toujours besoin de renuméroter la position des éléments suivants. Cependant, cela nécessite un peu plus d'efforts pour déterminer quand incrémenter les éléments suivants, donc vous perdez la simplicité mais gagnez en performances si vous avez plusieurs insertions.

En fonction de vos besoins, d'autres options peuvent plaire, telles que:

  • Si vous souhaitez effectuer de nombreuses manipulations sur la liste et pas beaucoup de récupérations, vous préférerez peut-être avoir une colonne ID pointant vers l'élément suivant dans la liste, au lieu d'utiliser une colonne de position. Ensuite, vous avez besoin d'une logique itérative dans la récupération de la liste afin de mettre les éléments en ordre. Cela peut être implémenté relativement facilement dans un proc stocké.

  • Si vous avez plusieurs listes, un moyen rapide de sérialiser et de désérialiser votre liste en texte/binaire, et que vous ne souhaitez que stocker et récupérer la liste entière, puis stocker la liste entière en tant que valeur unique dans une seule colonne. Mais ce n'est probablement pas ce que vous demandez ici.

4
Rory

https://dba.stackexchange.com/questions/46238/linked-list-in-sql-and-trees suggère une astuce d'utilisation de la colonne de position à virgule flottante pour des insertions et des commandes rapides.

Il mentionne également la fonctionnalité SQL Server 2014 hierarchyid spécialisée.

2
Vadzim

C'est quelque chose que j'essaie de comprendre depuis un moment moi-même. La meilleure façon que j'ai trouvée jusqu'à présent est de créer une seule table pour la liste chaînée en utilisant le format suivant (c'est du pseudo code):

LinkedList (

  • key1,
  • information,
  • clé2

)

key1 est le point de départ. Key2 est une clé étrangère se liant à elle-même dans la colonne suivante. Ainsi, vos colonnes relieront quelque chose de lien quelque chose comme ça

col1

  • key1 = 0,
  • information = 'bonjour'
  • key2 = 1

Key1 est la clé primaire de col1. key2 est une clé étrangère menant à key1 de col2

col2

  • key1 = 1,
  • information = 'wassup'
  • key2 = null

key2 de col2 est défini sur null car il ne pointe vers rien

Lorsque vous entrez une colonne pour la table pour la première fois, vous devez vous assurer que key2 est défini sur null ou vous obtiendrez une erreur. Après avoir entré la deuxième colonne, vous pouvez revenir en arrière et définir key2 de la première colonne sur la clé primaire de la deuxième colonne.

Cela constitue la meilleure méthode pour entrer de nombreuses entrées à la fois, puis revenir en arrière et définir les clés étrangères en conséquence (ou créer une interface graphique qui le fait juste pour vous)

Voici du code réel que j'ai préparé (tout le code réel a fonctionné sur MSSQL. Vous voudrez peut-être faire des recherches pour la version de SQL que vous utilisez!):

createtable.sql

create table linkedlist00 (

key1 int primary key not null identity(1,1),

info varchar(10),

key2 int

)

register_foreign_key.sql

alter table dbo.linkedlist00

add foreign key (key2) references dbo.linkedlist00(key1)

* Je les mets dans deux fichiers séparés, car cela doit être fait en deux étapes. MSSQL ne vous permettra pas de le faire en une seule étape, car la table n'existe pas encore pour la clé étrangère à référencer.

La liste liée est particulièrement puissante dans les relations un-à-plusieurs . Donc, si vous avez déjà voulu créer un tableau de clés étrangères? Eh bien, c'est une façon de le faire! Vous pouvez créer une table principale qui pointe vers la première colonne de la table de liste liée, puis au lieu du champ "informations", vous pouvez utiliser une clé étrangère pour la table d'informations souhaitée.

Exemple:

Disons que vous avez une bureaucratie qui conserve les formulaires.

Disons qu'ils ont une table appelée fichier CAB

FileCabinet (

  • ID de l'armoire (pk)
  • ID des fichiers (fk))

chaque colonne contient une clé primaire pour l'armoire et une clé étrangère pour les fichiers. Ces fichiers peuvent être des formulaires fiscaux, des papiers d'assurance maladie, des feuillets d'autorisation de sortie sur le terrain, etc.

Des dossiers(

  • ID de fichiers (pk)

  • ID de fichier (fk)

  • ID de fichier suivant (fk)

)

cela sert de conteneur pour les fichiers

Fichier(

  • ID de fichier (pk)

  • Informations sur le dossier

)

c'est le fichier spécifique

Il peut y avoir de meilleures façons de le faire et il y en a, selon vos besoins spécifiques. L'exemple illustre simplement une utilisation possible.

2
HumbleWebDev

Ce message est ancien mais va toujours donner mon 0,02 $. La mise à jour de chaque enregistrement dans une table ou un ensemble d'enregistrements semble fou pour résoudre l'ordre. la quantité d'indexation est également folle, mais il semble que la plupart l'ont acceptée.

La solution folle que j'ai trouvée pour réduire les mises à jour et l'indexation consiste à créer deux tables (et dans la plupart des cas, vous ne triez pas tous les enregistrements dans une seule table de toute façon). Tableau A pour contenir les enregistrements de la liste en cours de tri et tableau B pour regrouper et conserver un enregistrement de l'ordre sous forme de chaîne. la chaîne de commande représente un tableau qui peut être utilisé pour classer les enregistrements sélectionnés sur le serveur Web ou la couche de navigateur d'une application de page Web.

Create Table A{
Id int primary key identity(1,1),
Data varchar(10) not null
B_Id int
}

Create Table B{
Id int primary key Identity(1,1),
GroupName varchat(10) not null,
Order varchar(max) null
}

Le format de la piqûre de commande doit être id, position et un séparateur pour séparer () votre chaîne. dans le cas de jQuery UI, la fonction .sortable ('serialize') génère pour vous une chaîne de commande qui est POST conviviale qui inclut l'id et la position de chaque enregistrement dans la liste.

La vraie magie est la façon dont vous choisissez de réorganiser la liste sélectionnée en utilisant la chaîne de commande enregistrée. cela dépendra de l'application que vous construisez. voici à nouveau un exemple de jQuery pour réorganiser la liste des éléments: http://ovisdevelopment.com/oramincite/?p=155

2
FlyTigert

Incrémentez l '"index" SERIAL de 100, mais ajoutez manuellement des valeurs intermédiaires avec un "index" égal à Précédent + Suivant/2. Si vous avez déjà saturé les 100 lignes, réorganisez l'index à 100 s.

Cela devrait maintenir la séquence avec l'index primaire.

1
Stephen

Il y a quelques approches auxquelles je peux penser immédiatement, chacune avec des niveaux différents de complexité et de flexibilité. Je suppose que votre objectif est de conserver une commande lors de la récupération, plutôt que d'exiger le stockage en tant que liste chaînée réelle.

La méthode la plus simple serait d'attribuer une valeur ordinale à chaque enregistrement du tableau (par exemple 1, 2, 3, ...). Ensuite, lorsque vous récupérez les enregistrements, spécifiez un ordre de tri dans la colonne ordinale pour les remettre en ordre.

Cette approche vous permet également de récupérer les enregistrements sans tenir compte de l'appartenance à une liste, mais autorise l'appartenance à une seule liste et peut nécessiter une colonne "id de liste" supplémentaire pour indiquer à quelle liste appartient l'enregistrement.

Une approche un peu plus élaborée, mais aussi plus flexible, consisterait à stocker les informations sur l'appartenance à une ou plusieurs listes dans un tableau séparé. La table aurait besoin de 3 colonnes: l'ID de la liste, la valeur ordinale et un pointeur de clé étrangère vers l'enregistrement de données. Selon cette approche, les données sous-jacentes ne savent rien de leur appartenance à des listes et peuvent facilement être incluses dans plusieurs listes.

1
Mike Monette

Je pense qu'il est beaucoup plus simple d'ajouter une colonne créée de type Datetime et une colonne de position de int, donc maintenant vous pouvez avoir des positions en double, à l'instruction select, utilisez le order by position, option desc créée et votre liste sera récupérée dans l'ordre.

1
Poncho

Une liste peut être stockée en ayant une colonne contenant le décalage (position d'index de la liste) - un insert au milieu est ensuite incrémenté tout au-dessus du nouveau parent puis fait un insert.

0
Daniel Papasian