次の表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 |
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+------------------------------+-------------+------------------+
ご覧のとおり、この場合、同じ値field_seq
を持つ2つの36
があります。
field_id=281960
の直後に新しい行を挿入していて、そのような新しい行のfield_seq
が36
として来るとします。
field_seq
が36
以上の行があるかどうかを確認できるクエリまたはストアドプロシージャを作成する必要があります。その場合は、field_seq
の値を現在の値と1
に更新します。
例:
INSERT INTO `fields` VALUES(9999, 9926, NULL, 0, 41, 1, 5, 36, 'lllll', NULL, NULL);
これにより、以下の可能なケースを確認できます(それぞれの後に例を示します)。
ケース1: field_seq = 36の行はすでにテーブルに存在します
field_seq=36
新しい行になります。field_seq=current+1
になるテーブル行37
の値を更新します37
がすでにある場合は、field_seq
が繰り返されなくなるまで前のステップを繰り返します。前:
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+-------------+-------------+------------------+
| 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 |
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+-------------+-------------+------------------+
後:
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+---------------------+-------------+------------------+
| 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
+----------+---------+-----------------+-------------+---------+--------------+---------------+-----------+---------------------+-------------+------------------+
ケース2: field_seq = 36の行はすでにテーブルに存在しますが、次のfield_seq
は37
より大きいです
field_seq=36
新しい行になります。field_seq=current+1
になるテーブル行37
の値を更新しますfield_seq
になる前に数行を挿入するのに十分なスペースがあるため、更新を続ける必要はありません。前:
+----------+---------+-----------------+-------------+---------+---------------+---------------+-----------+------------+-------------+
| 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 |
+----------+---------+-----------------+-------------+---------+---------------+---------------+-----------+------------+-------------+
後:
+----------+---------+-----------------+-------------+---------+---------------+---------------+-----------+------------+-------------+
| 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
+----------+---------+-----------------+-------------+---------+---------------+---------------+-----------+------------+-------------+
Microsoft SQL Server 2016(SP1)を使用しています。どうすればこれを達成できますか?
あなたはこれを試してみることができます:
--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
コードは、field_seq.
に競合があるかどうかを確認します。競合がある場合は、テーブルをスキャンして次のギャップを見つけ、その範囲のfield_seq
値をすべて更新して、新しいレコードを挿入するギャップ。衝突が見つからない場合、更新はスキップされます。ただし、これについてはパフォーマンスを保証できません。それを行うためのより最適な方法があると確信しています。
これが dbfiddle です。更新が行われる前と後に、挿入が行われるためにギャップが生じていることがわかります。
エラーハンドラーを追加し、TRANSACTIONを使用して、影響を受けるすべてのレコードが確実に更新されるようにしてください。
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行が影響を受けました
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
✓
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
最後に新しいレコードを挿入します。
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 ここ
挿入ではサブクエリをいつでも使用できます。
INSERT INTO `fields` VALUES(9999, 9926, NULL, 0, 41, 1, 5, (SELECT MAX(field_seq) + 1 FROM fields), 'lllll', NULL, NULL);
うまくいくかもしれません