Объявить переменную в SQLite и использовать ее


94

Я хочу объявить переменную в SQLite и использовать ее в insertработе.

Как в MS SQL:

declare @name as varchar(10)
set name = 'name'
select * from table where name = @name

Например, мне нужно будет получить last_insert_rowи использовать его в insert.

Я кое-что нашел о привязке, но не совсем понял это.


7
sqlite не поддерживает это.
Дэн Д.

2
надеюсь, что сейчас есть лучшее решение - август 2018
MarshallMa

Ответы:


93

SQLite не поддерживает собственный синтаксис переменных, но вы можете добиться того же, используя временную таблицу в памяти.

Я использовал нижеприведенный подход для больших проектов, и он отлично работает.

    /* Create in-memory temp table for variables */
    BEGIN;

    PRAGMA temp_store = 2;
    CREATE TEMP TABLE _Variables(Name TEXT PRIMARY KEY, RealValue REAL, IntegerValue INTEGER, BlobValue BLOB, TextValue TEXT);

    /* Declaring a variable */
    INSERT INTO _Variables (Name) VALUES ('VariableName');

    /* Assigning a variable (pick the right storage class) */
    UPDATE _Variables SET IntegerValue = ... WHERE Name = 'VariableName';

    /* Getting variable value (use within expression) */
    ... (SELECT coalesce(RealValue, IntegerValue, BlobValue, TextValue) FROM _Variables WHERE Name = 'VariableName' LIMIT 1) ...

    DROP TABLE _Variables;
    END;

Для чего используются эти [] скобки?
WindRider

1
@WindRider: чтобы избежать конфликтов с зарезервированными словами. Моя привычка, но в данном случае она не нужна, поэтому они удалены.
Herman Schoenfeld

2
Это работает, но есть несколько замечаний, я пробовал это на Spaceite, и там говорится, что вы не можете изменить временное хранилище из транзакции. Кроме того, я думаю, вам не хватает точки с запятой после BEGIN. Tx за то, что поделились этим решением.
Glenn Plas

Как это увеличить? Я имею в виду, как увеличивать эту переменную, как если бы она увеличивалась с последовательными вызовами.
Вибху Джайн

2
Временные таблицы не обязательно находятся в памяти . Это зависит от параметров компилятора, а также от PRAGMA temp_storeнастройки. Фактически, согласно онлайн-документации , настройка по умолчанию - временное хранение файлов на диск (который включает файлы для временных таблиц и индексов).
C Perkins

43

Решение Германа работает, но его можно упростить, потому что Sqlite позволяет хранить любой тип значения в любом поле.

Вот более простая версия, в которой используется одно Valueполе, объявленное TEXTдля хранения любого значения:

CREATE TEMP TABLE IF NOT EXISTS Variables (Name TEXT PRIMARY KEY, Value TEXT);

INSERT OR REPLACE INTO Variables VALUES ('VarStr', 'Val1');
INSERT OR REPLACE INTO Variables VALUES ('VarInt', 123);
INSERT OR REPLACE INTO Variables VALUES ('VarBlob', x'12345678');

SELECT Value
  FROM Variables
 WHERE Name = 'VarStr'
UNION ALL
SELECT Value
  FROM Variables
 WHERE Name = 'VarInt'
UNION ALL
SELECT Value
  FROM Variables
 WHERE Name = 'VarBlob';

3
но вы не должны забывать приводить значение к правильному типу, если хотите использовать его для сравнений, иначе вы можете получить удивительные результаты
vlad_tepesch

33

Для переменной, доступной только для чтения (то есть постоянного значения, установленного один раз и используемого в любом месте запроса), используйте Common Table Expression (CTE).

WITH const AS (SELECT 'name' AS name, 10 AS more)
SELECT table.cost, (table.cost + const.more) AS newCost
FROM table, const 
WHERE table.name = const.name

Предложение SQLite WITH


2
Это самый элегантный ответ imo
Vladtn

1
Это тот ответ, который я искал.
Джон Бабер-Лусеро,

9

Решение Германа сработало для меня, но ...меня немного запутали. Я включаю демонстрацию, которую разработал на основе его ответа. Дополнительные функции в моем ответе включают поддержку внешнего ключа, автоматическое увеличение ключей и использование last_insert_rowid()функции для получения последнего автоматически сгенерированного ключа в транзакции.

Моя потребность в этой информации возникла, когда я попал в транзакцию, для которой требовалось три внешних ключа, но я мог получить только последний last_insert_rowid().

PRAGMA foreign_keys = ON;   -- sqlite foreign key support is off by default
PRAGMA temp_store = 2;      -- store temp table in memory, not on disk

CREATE TABLE Foo(
    Thing1 INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
);

CREATE TABLE Bar(
    Thing2 INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    FOREIGN KEY(Thing2) REFERENCES Foo(Thing1)
);

BEGIN TRANSACTION;

CREATE TEMP TABLE _Variables(Key TEXT, Value INTEGER);

INSERT INTO Foo(Thing1)
VALUES(2);

INSERT INTO _Variables(Key, Value)
VALUES('FooThing', last_insert_rowid());

INSERT INTO Bar(Thing2)
VALUES((SELECT Value FROM _Variables WHERE Key = 'FooThing'));

DROP TABLE _Variables;

END TRANSACTION;

спасибо за хороший пример, действительно намного полезнее, чем мнения и ссылки
splaisan

-1

Попробуйте использовать значения привязки. Вы не можете использовать переменные, как в T-SQL, но можете использовать «параметры». Надеюсь, следующая ссылка окажется полезной. Обязательные значения


26
вы можете сделать свой ответ более насыщенным, приведя примеры. Ссылки можно перемещать, но ваши примеры будут здесь для дальнейшего использования.
Pabluez
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.