J'ai le tableau suivant fields
:
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+------------------------------+-------------+------------------+
| field_id | form_id | form_section_id | is_required | grid_id | is_base_grid | field_type_id | field_seq | field_name | field_class | field_class_data |
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+------------------------------+-------------+------------------+
| 220481 | 9926 | NULL | 0 | NULL | NULL | 4 | 28 | Test | NULL | NULL |
| 281863 | 9926 | NULL | 0 | NULL | NULL | 10 | 29 | insert after yes no question | NULL | NULL |
| 220496 | 9926 | NULL | 0 | 11 | 1 | 5 | 30 | test | NULL | NULL |
| 249234 | 9926 | NULL | 0 | 12 | 1 | 5 | 32 | | NULL | NULL |
| 279877 | 9926 | NULL | 0 | NULL | NULL | 4 | 33 | Test Text Questions | NULL | NULL |
| 281860 | 9926 | NULL | 0 | NULL | NULL | 10 | 34 | Something | NULL | NULL |
| 281914 | 9926 | NULL | 0 | 23 | 1 | 5 | 35 | sssss | NULL | NULL |
| 281960 | 9926 | NULL | 0 | 38 | 1 | 5 | 36 | yuyuyu | NULL | NULL |
| 281972 | 9926 | NULL | 0 | 40 | 1 | 5 | 40 | ttttt | NULL | NULL |
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+------------------------------+-------------+------------------+
Comme vous pouvez le voir, il existe deux field_seq
avec la même valeur 36
dans ce cas.
Supposons que j'insère une nouvelle ligne juste après field_id=281960
et le field_seq
pour cette nouvelle ligne arrive comme 36
.
J'ai besoin de construire une requête ou même une procédure stockée où je peux savoir s'il y a une ligne avec field_seq
égal ou supérieur à 36
et si oui, mettez à jour la valeur de field_seq
à la valeur actuelle plus 1
.
Ex:
INSERT INTO `fields` VALUES(9999, 9926, NULL, 0, 41, 1, 5, 36, 'lllll', NULL, NULL);
Ayant cela voir les cas possibles ci-dessous (avec des exemples après chacun):
Cas 1: la ligne avec field_seq = 36 existe déjà sur la table
field_seq=36
nouvelle lignefield_seq=current+1
qui deviendra 37
37
déjà puis répétez l'étape précédente jusqu'à ce qu'il n'y ait plus de répétition field_seq
Avant:
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+-------------+-------------+------------------+
| field_id | form_id | form_section_id | is_required | grid_id | is_base_grid | field_type_id | field_seq | field_nanme | field_class | field_class_data |
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+-------------+-------------+------------------+
| 281914 | 9926 | NULL | 0 | 23 | 1 | 5 | 32 | sssss | NULL | NULL |
| 281972 | 9926 | NULL | 0 | 40 | 1 | 5 | 36 | ttttt | NULL | NULL |
| 281960 | 9926 | NULL | 0 | 38 | 1 | 5 | 37 | yuyuyu | NULL | NULL |
| 281978 | 9926 | NULL | 0 | 38 | 1 | 5 | 38 | vvvvv | NULL | NULL |
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+-------------+-------------+------------------+
Après:
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+---------------------+-------------+------------------+
| field_id | form_id | form_section_id | is_required | grid_id | is_base_grid | field_type_id | field_seq | field_nanme | field_class | field_class_data |
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+---------------------+-------------+------------------+
| 281914 | 9926 | NULL | 0 | 23 | 1 | 5 | 32 | sssss | NULL | NULL |
| 9999 | 9926 | NULL | 0 | 41 | 1 | 5 | 36 | lllll | NULL | NULL | => new row inserted here
| 281972 | 9926 | NULL | 0 | 40 | 1 | 5 | 37 | ttttt | NULL | NULL | => this was 36 now is updated to 37
| 281960 | 9926 | NULL | 0 | 38 | 1 | 5 | 38 | yuyuyu | NULL | NULL | => this was 37 now is updated to 38
| 281978 | 9926 | NULL | 0 | 38 | 1 | 5 | 39 | vvvvv | NULL | NULL | => this was 38 now is updated to 39
| 220524 | 9926 | NULL | 0 | NULL | NULL | 5 | 40 | Patient Information | NULL | NULL | => we don't care about this cause there is room for one more, if one insert makes the rows above become 40 then this needs to be updated to 41
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+---------------------+-------------+------------------+
Cas 2: ligne avec field_seq = 36 existe déjà sur la table mais à côté field_seq
est supérieur à 37
field_seq=36
nouvelle lignefield_seq=current+1
qui deviendra 37
field_seq
Avant:
+----------+---------+-----------------+-------------+---------+---------------+---------------+-----------+------------+-------------+
| field_id | form_id | form_section_id | is_required | grid_id | is_base_grid | field_type_id | field_seq | field_name | field_class |
+----------+---------+-----------------+-------------+---------+---------------+---------------+-----------+------------+-------------+
| 281914 | 9926 | NULL | 0 | 23 | 1 | 5 | 32 | sssss | NULL |
| 281972 | 9926 | NULL | 0 | 40 | 1 | 5 | 36 | ttttt | NULL |
| 281972 | 9926 | NULL | 0 | 40 | 1 | 5 | 40 | ooooo | NULL |
+----------+---------+-----------------+-------------+---------+---------------+---------------+-----------+------------+-------------+
Après:
+----------+---------+-----------------+-------------+---------+---------------+---------------+-----------+------------+-------------+
| field_id | form_id | form_section_id | is_required | grid_id | is_base_grid | field_type_id | field_seq | field_name | field_class |
+----------+---------+-----------------+-------------+---------+---------------+---------------+-----------+------------+-------------+
| 281914 | 9926 | NULL | 0 | 23 | 1 | 5 | 32 | sssss | NULL |
| 281972 | 9926 | NULL | 0 | 41 | 1 | 5 | 36 | lllll | NULL | => new row inserted here
| 281972 | 9926 | NULL | 0 | 40 | 1 | 5 | 37 | ttttt | NULL | => previous row with field_seq=36 was updated to 37
| 281972 | 9926 | NULL | 0 | 40 | 1 | 5 | 40 | ooooo | NULL | => nothing happen to this one since there is room for more
+----------+---------+-----------------+-------------+---------+---------------+---------------+-----------+------------+-------------+
J'utilise Microsoft SQL Server 2016 (SP1). Comment puis-je y parvenir?
Vous pouvez essayer ceci:
--enter procedure with insert parameters
DECLARE @field_seq INT = 36
DECLARE @field_seq_range INT
IF EXISTS(SELECT * FROM fields WHERE field_seq = @field_seq)
BEGIN
SELECT @field_seq_range = MIN(f.field_seq)
FROM (
SELECT field_seq, LEAD(field_seq, 1, NULL) OVER (ORDER BY field_seq) next_field_seq
FROM fields
) f
WHERE f.field_seq >= @field_seq
AND f.field_seq + 1 < f.next_field_seq
UPDATE f
SET f.field_seq = f.field_seq + 1
FROM fields f
WHERE f.field_seq BETWEEN @field_seq AND @field_seq_range
END
--perform insert
Le code va vérifier s'il y a une collision sur field_seq.
S'il y en a un, il va scanner le tableau pour trouver le prochain écart, mettre à jour tous les field_seq
valeurs dans cette plage et laissez un espace pour insérer le nouvel enregistrement. Si aucune collision n'est trouvée, la mise à jour est ignorée. Cependant, je ne peux garantir aucune performance. Je suis sûr qu'il existe des moyens plus optimaux de le faire.
Voici le dbfiddle - vous pouvez voir avant et après la mise à jour, créant un espace pour l'insertion.
N'oubliez pas que vous devez ajouter un gestionnaire d'erreurs et utiliser une TRANSACTION pour vous assurer que tous les enregistrements concernés sont mis à jour.
CREATE TABLE T(field_id int, field_seq int); INSERT INTO T VALUES (22156, 28), (22759, 29), (23458, 30), (28000, 31), (28101, 32), (29355, 33), (30000, 34), (30125, 35); GO
8 lignes affectées
CREATE PROCEDURE InsertNewID(@new_id int) AS BEGIN DECLARE @field_seq int = 0, @field_id int = 0; -- try to find if there is some field_id > @new_id SELECT TOP 1 @field_id = COALESCE(field_id, 0), @field_seq = COALESCE(field_seq, 0) FROM T WHERE field_id > @new_id ORDER BY field_id ASC; -- if there isn't any field_id > @new_id -- get MAX(field_seq) OR 1 in case there is no records IF @field_seq = 0 BEGIN SELECT @field_seq = COALESCE(MAX(field_seq), 0) + 1 FROM T END IF @field_id > 0 BEGIN UPDATE T SET field_seq = field_seq + 1 WHERE field_id >= @field_id END INSERT INTO T (field_id, field_seq) VALUES (@new_id, @field_seq); END GO
✓
Insérer un nouvel enregistrement après field_id=29355
EXEC InsertNewId @new_id = 29999; SELECT * FROM T ORDER BY field_id; GO
field_id | field_seq -------: | --------: 22156 | 28 22759 | 29 23458 | 30 28000 | 31 28101 | 32 29355 | 33 29999 | 34 30000 | 35 30125 | 36
Insérez un nouvel enregistrement à la fin.
EXEC InsertNewId @new_id = 31000; SELECT * FROM T ORDER BY field_id; GO
field_id | field_seq -------: | --------: 22156 | 28 22759 | 29 23458 | 30 28000 | 31 28101 | 32 29355 | 33 29999 | 34 30000 | 35 30125 | 36 31000 | 37
dbfiddle ici
Vous pouvez toujours utiliser une sous-requête dans votre insert, quelque chose comme ....
INSERT INTO `fields` VALUES(9999, 9926, NULL, 0, 41, 1, 5, (SELECT MAX(field_seq) + 1 FROM fields), 'lllll', NULL, NULL);
pourrait fonctionner