Zadeklaruj zmienną w SQLite i użyj jej

94

Chcę zadeklarować zmienną w SQLite i używać jej w insertdziałaniu.

Podobnie jak w MS SQL:

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

Na przykład będę musiał go pobrać last_insert_rowi użyć w insert.

Znalazłem coś na temat wiązania, ale nie do końca to zrozumiałem.

Muhammad Nour
źródło
7
sqlite tego nie obsługuje.
Dan D.
2
mam nadzieję, że jest teraz lepsze rozwiązanie - sie 2018
MarshallMa

Odpowiedzi:

93

SQLite nie obsługuje natywnej składni zmiennych, ale możesz osiągnąć praktycznie to samo, używając tabeli tymczasowej w pamięci.

Użyłem poniższego podejścia do dużych projektów i działa jak urok.

    /* 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;
Herman Schoenfeld
źródło
Do czego służą te [] nawiasy?
WindRider
1
@WindRider: aby uniknąć kolizji ze słowami zastrzeżonymi. Mój nawyk, ale w tym przypadku niepotrzebny, więc są usuwane.
Herman Schoenfeld
2
To działa, ale jest kilka uwag, wypróbowałem to na spatialite i tam jest napisane, że nie możesz zmienić tymczasowego sklepu z poziomu transakcji. Myślę też, że po BEGIN brakuje średnika. Tx za udostępnienie tego rozwiązania.
Glenn Plas,
Jak to zwiększyć? Mam na myśli, jak inkrementować tę zmienną tak, jakby zwiększała się o kolejne wywołania.
Vibhu Jain
2
Nie ma gwarancji, że tabele tymczasowe znajdują się w pamięci . Zależy to od opcji kompilatora, a także PRAGMA temp_storeustawienia. W rzeczywistości, zgodnie z dokumentacją online , domyślnym ustawieniem jest tymczasowe przechowywanie plików na dysku (co obejmuje pliki tymczasowych tabel i indeksów).
C Perkins
43

Rozwiązanie Hermana działa, ale można je uprościć, ponieważ Sqlite umożliwia przechowywanie dowolnego typu wartości w dowolnym polu.

Oto prostsza wersja, która używa jednego Valuepola zadeklarowanego jako TEXTdo przechowywania dowolnej wartości:

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';
stenci
źródło
3
ale nie należy zapominać o rzutowaniu wartości na właściwy typ, jeśli chcesz użyć jej w porównaniach lub możesz uzyskać zaskakujące wyniki
vlad_tepesch
33

W przypadku zmiennej tylko do odczytu (czyli stałej ustawionej raz i używanej w dowolnym miejscu w zapytaniu) użyj wspólnego wyrażenia tabelowego (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

Klauzula SQLite WITH

DenverCR
źródło
2
To najbardziej elegancka odpowiedź imo
Vladtn
1
To jest typ odpowiedzi, którego szukałem.
John Baber-Lucero
9

Rozwiązanie Hermana zadziałało dla mnie, ale ...trochę mnie pomieszało. Załączam wersję demonstracyjną, którą opracowałem na podstawie jego odpowiedzi. Dodatkowe funkcje w mojej odpowiedzi obejmują obsługę kluczy obcych, automatyczne zwiększanie kluczy i użycie last_insert_rowid()funkcji w celu uzyskania ostatniego automatycznie wygenerowanego klucza w transakcji.

Moje zapotrzebowanie na te informacje pojawiło się, gdy trafiłem na transakcję wymagającą trzech kluczy obcych, ale mogłem uzyskać tylko ostatni z nich 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;
ThisClark
źródło
dzięki za fajny przykład, rzeczywiście dużo bardziej przydatny niż opinie i linki
splaisan
-1

Spróbuj użyć wartości wiążących. Nie możesz używać zmiennych, tak jak w T-SQL, ale możesz używać „parametrów”. Mam nadzieję, że poniższy link jest przydatny. Wiążące wartości

Nieznany
źródło
26
możesz wzbogacić swoją odpowiedź, podając przykłady. Linki można przenosić, ale przykłady będą tutaj do wykorzystania w przyszłości.
Pabluez