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.


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;

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';

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


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;

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


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.