Вставьте предыдущее значение поля, используя INSERT INTO и подзапрос SELECT - PullRequest
0 голосов
/ 16 апреля 2020

У меня есть следующая схема:

CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, val INTEGER, previousval INTEGER)

Я хочу сохранить значение val и автоматически скопировать предыдущее значение в столбец previousval:

id  val previousval
1   100 NULL
2   200 100
3   300 200

I пробовал следующий запрос и SQLite выдает мне сообщение об ошибке, которое я не понимаю.

INSERT INTO test as test1 (id, val, previousval) VALUES (NULL, 1, (SELECT test2.val FROM test AS test2 WHERE test2.id<test1.id ORDER BY test2.id DESC LIMIT 1))
> no such column: test1.id

Я пробовал другой запрос:

INSERT INTO test (id, val, previousval) VALUES (NULL, 100, (SELECT test2.val FROM test AS test2 WHERE test2.id<id ORDER BY test2.id DESC LIMIT 1)) 
INSERT INTO test (id, val, previousval) VALUES (NULL, 200, (SELECT test2.val FROM test AS test2 WHERE test2.id<id ORDER BY test2.id DESC LIMIT 1)) 
INSERT INTO test (id, val, previousval) VALUES (NULL, 300, (SELECT test2.val FROM test AS test2 WHERE test2.id<id ORDER BY test2.id DESC LIMIT 1)) 

Результат не тот, который я ожидаю, и я не Не понимаю, почему.

id  val previousval
1   100 NULL
2   200 NULL
3   300 NULL

Я использую sqlite-amalgamation-3310100. Я также использую SQLiteStudio для тестирования.

Как автоматически скопировать значение поля в столбец, используя INSERT INTO?

Ответы [ 2 ]

1 голос
/ 16 апреля 2020

Проблема с вашей попыткой состоит в том, что вы пытаетесь сопоставить подзапрос со значением, которое еще не вставлено. Это не может работать.

Вы можете просто сделать:

insert into test as test1 (id, val, previousval) 
values(
    null, 
    1, 
    (select val from test order by id desc limit 1)
)

Примечание: если id - это автоинкрементный ключ (как это выглядит), тогда просто пропустите этот столбец при вставке:

insert into test as test1 (val, previousval) 
values(
    1, 
    (select val from test order by id desc limit 1)
)

Итог, я бы на самом деле не рекомендовал сохранять эту производную информацию в самой таблице: например, если val обновлен, то вам потребуется дополнительная обработка для сброса следующей записи ,

Вы можете легко вычислить эту информацию на лету, когда это необходимо, или поместить в представление. Если ваша версия SQLite поддерживает оконные функции:

select id, val, lag(val) over(order by id) previousval from mytable

В более ранних версиях:

select
    t.id,
    t.val,
    (select val from mytable t1 where t1.id < t.id order by t1.id desc limit 1) previousval
from mytable t
0 голосов
/ 16 апреля 2020

В вашем CREATE выражении таблицы вы определяете столбец id как:

id INTEGER PRIMARY KEY 

, и это означает, что он будет уникальным и будет автоматически увеличен. Но это не значит, что оно всегда будет расти. Если вы удалите строку, в следующий раз, когда вы вставите новую строку, значение отсутствует идентификатор может быть повторно использовано, поэтому логика c, которую вы хотите применить, не будет работать. Итак, как объясняется здесь , вы должны отключить повторное использование идентификаторов, и это можно сделать с помощью ключевого слова AUTOINCREMENT в определении столбца:

CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, ...) 

Тогда вы можно вставить новые строки, как это:

INSERT INTO test(val, previousval) VALUES
(100, (SELECT val FROM test ORDER BY id DESC LIMIT 1));
INSERT INTO test(val, previousval) VALUES       
(200, (SELECT val FROM test ORDER BY id DESC LIMIT 1));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...