Frage

In MS SQL Server erstelle ich meine Skripte, um anpassbare Variablen zu verwenden:

DECLARE @somevariable int  
SELECT @somevariable = -1

INSERT INTO foo VALUES ( @somevariable )

Ich werde dann den Wert von ändern @somevariable zur Laufzeit, abhängig von dem Wert, den ich in der jeweiligen Situation haben möchte.Da es oben im Skript steht, ist es leicht zu sehen und zu merken.

Wie mache ich dasselbe mit dem PostgreSQL-Client? psql?

War es hilfreich?

Lösung

Postgres-Variablen werden beispielsweise mit dem Befehl \set erstellt ...

\set myvariable value

...und kann dann beispielsweise ersetzt werden als ...

SELECT * FROM :myvariable.table1;

...oder ...

SELECT * FROM table1 WHERE :myvariable IS NULL;

bearbeiten:Ab psql 9.1 können Variablen wie folgt in Anführungszeichen erweitert werden:

\set myvariable value 

SELECT * FROM table1 WHERE column1 = :'myvariable';

In älteren Versionen des psql-Clients:

...Wenn Sie die Variable als Wert in einer bedingten Zeichenfolgenabfrage verwenden möchten, z. B. ...

SELECT * FROM table1 WHERE column1 = ':myvariable';

...Dann müssen Sie die Anführungszeichen in die Variable selbst einfügen, da das oben Gesagte nicht funktioniert.Definieren Sie stattdessen Ihre Variable als solche ...

\set myvariable 'value'

Wenn Sie jedoch, wie ich, in eine Situation geraten sind, in der Sie aus einer vorhandenen Variablen einen String erstellen möchten, ist für mich folgender Trick zu finden ...

\set quoted_myvariable '\'' :myvariable '\''

Jetzt haben Sie sowohl eine in Anführungszeichen gesetzte als auch eine nicht in Anführungszeichen gesetzte Variable derselben Zeichenfolge!Und Sie können so etwas tun ...

INSERT INTO :myvariable.table1 SELECT * FROM table2 WHERE column1 = :quoted_myvariable;

Andere Tipps

Ein letztes Wort zu PSQL-Variablen:

  1. Sie werden nicht erweitert, wenn Sie sie in der SQL-Anweisung in einfache Anführungszeichen setzen.Das funktioniert also nicht:

    SELECT * FROM foo WHERE bar = ':myvariable'
    
  2. Um in einer SQL-Anweisung zu einem Zeichenfolgenliteral zu erweitern, müssen Sie die Anführungszeichen in den Variablensatz aufnehmen.Allerdings muss der Variablenwert bereits in Anführungszeichen gesetzt werden, was bedeutet, dass Sie einen benötigen zweite Satz von Anführungszeichen, und der innere Satz muss maskiert werden.Sie benötigen also:

    \set myvariable '\'somestring\''  
    SELECT * FROM foo WHERE bar = :myvariable
    

    BEARBEITEN:Ab PostgreSQL 9.1 können Sie stattdessen Folgendes schreiben:

    \set myvariable somestring
    SELECT * FROM foo WHERE bar = :'myvariable'
    

Sie können versuchen, a zu verwenden MIT Klausel.

WITH vars AS (SELECT 42 AS answer, 3.14 AS appr_pi)
SELECT t.*, vars.answer, t.radius*vars.appr_pi
FROM table AS t, vars;

Speziell für psql, Sie können durch psql Variablen auch über die Befehlszeile;Du kannst sie mit weitergeben -v.Hier ist ein Anwendungsbeispiel:

$ psql -v filepath=/path/to/my/directory/mydatafile.data regress
regress=> SELECT :'filepath';
               ?column?                
---------------------------------------
 /path/to/my/directory/mydatafile.data
(1 row)

Beachten Sie, dass der Doppelpunkt nicht in Anführungszeichen gesetzt ist und der Variablenname selbst in Anführungszeichen gesetzt wird.Seltsame Syntax, ich weiß.Dies funktioniert nur in psql;es wird nicht in (sagen wir) PgAdmin-III funktionieren.

Diese Ersetzung erfolgt während der Eingabeverarbeitung in psql, sodass Sie beispielsweise keine Funktion definieren können, die verwendet :'filepath' und erwarte den Wert von :'filepath' um von Sitzung zu Sitzung zu wechseln.Es wird einmal ersetzt, wenn die Funktion definiert wird, und ist danach eine Konstante.Es ist für die Skripterstellung nützlich, aber nicht zur Laufzeit.

FWIW, das eigentliche Problem war, dass ich am Ende meines \set-Befehls ein Semikolon eingefügt hatte:

\setowner_password 'thepassword';

Das Semikolon wurde als tatsächliches Zeichen in der Variablen interpretiert:

echo: Eigentümer_Password ThePassword;

Als ich versuchte, es zu verwenden:

ROLLE ERSTELLEN myrole LOGIN UNVERSCHLÜSSELTES PASSWORT:owner_password NOINHERIT CREATEDB CREATEROLE GÜLTIG BIS 'unendlich';

...Ich schaff das:

ROLLE ERSTELLEN myrole LOGIN UNVERSCHLÜSSELTES PASSWORT thepassword;NOINHERIT CREATEDB CREATEROLE GÜLTIG BIS 'unendlich';

Dadurch konnten nicht nur die Anführungszeichen um das Literal nicht gesetzt werden, sondern der Befehl wurde auch in zwei Teile aufgeteilt (von denen der zweite ungültig war, da er mit „NOINHERIT“ begann).

Die Moral dieser Geschichte:PostgreSQL-„Variablen“ sind eigentlich Makros, die bei der Texterweiterung verwendet werden, keine echten Werte.Ich bin mir sicher, dass das praktisch ist, aber am Anfang ist es schwierig.

Sie müssen eine der prozeduralen Sprachen wie PL/pgSQL verwenden, nicht die SQL-Proc-Sprache.In PL/pgSQL können Sie Variablen direkt in SQL-Anweisungen verwenden.Für einfache Anführungszeichen können Sie die Quote-Literal-Funktion verwenden.

Postgres (seit Version 9.0) ermöglicht anonyme Blöcke in allen unterstützten serverseitigen Skriptsprachen

DO '
DECLARE somevariable int = -1;
BEGIN
INSERT INTO foo VALUES ( somevariable );
END
' ;

http://www.postgresql.org/docs/current/static/sql-do.html

Da sich alles in einem String befindet, müssen externe String-Variablen, die ersetzt werden, mit Escapezeichen versehen und zweimal in Anführungszeichen gesetzt werden.Die Verwendung von Dollar-Quoting bietet stattdessen keinen vollständigen Schutz gegen SQL-Injection.

Ein anderer Ansatz besteht darin, den PostgreSQL-GUC-Mechanismus zum Erstellen von Variablen (ab)zunutzen.Sehen diese vorherige Antwort für Details und Beispiele.

Sie erklären den GUC in postgresql.conf, und ändern Sie dann seinen Wert zur Laufzeit mit SET Befehle und erhalten Sie ihren Wert mit current_setting(...).

Ich empfehle dies nicht für den allgemeinen Gebrauch, aber es könnte in engen Fällen wie dem in der verlinkten Frage erwähnten nützlich sein, in dem der Autor eine Möglichkeit suchte, Triggern und Funktionen den Benutzernamen auf Anwendungsebene bereitzustellen.

Ich habe es mit einer temporären Tabelle gelöst.

CREATE TEMP TABLE temp_session_variables (
    "sessionSalt" TEXT
);
INSERT INTO temp_session_variables ("sessionSalt") VALUES (current_timestamp || RANDOM()::TEXT);

Auf diese Weise hatte ich eine „Variable“, die ich für mehrere Abfragen verwenden konnte und die für die Sitzung eindeutig ist.Ich brauchte es, um eindeutige „Benutzernamen“ zu generieren, ohne dass es beim Importieren von Benutzern mit demselben Benutzernamen zu Kollisionen kam.

Ich fand diese Frage und die Antworten äußerst nützlich, aber auch verwirrend.Ich hatte große Probleme damit, in Anführungszeichen gesetzte Variablen zum Laufen zu bringen, also habe ich es wie folgt zum Laufen gebracht:

\set deployment_user username    -- username
\set deployment_pass '\'string_password\''
ALTER USER :deployment_user WITH PASSWORD :deployment_pass;

Auf diese Weise können Sie die Variable in einer Anweisung definieren.Wenn Sie es verwenden, werden einfache Anführungszeichen in die Variable eingebettet.

NOTIZ!Wenn ich nach der in Anführungszeichen gesetzten Variablen einen Kommentar einfüge, wurde dieser als Teil der Variablen übernommen, als ich einige der Methoden in anderen Antworten ausprobierte.Das hat mich eine Zeit lang wirklich durcheinander gebracht.Mit dieser Methode werden Kommentare scheinbar wie erwartet behandelt.

Ich vermisse diese Funktion wirklich.Der einzige Weg, etwas Ähnliches zu erreichen, ist die Verwendung von Funktionen.

Ich habe es auf zwei Arten verwendet:

  • Perl-Funktionen, die die Variable $_SHARED verwenden
  • Speichern Sie Ihre Variablen in der Tabelle

Perl-Version:

   CREATE FUNCTION var(name text, val text) RETURNS void AS $$
        $_SHARED{$_[0]} = $_[1];
   $$ LANGUAGE plperl;
   CREATE FUNCTION var(name text) RETURNS text AS $$
        return $_SHARED{$_[0]};
   $$ LANGUAGE plperl;

Tischversion:

CREATE TABLE var (
  sess bigint NOT NULL,
  key varchar NOT NULL,
  val varchar,
  CONSTRAINT var_pkey PRIMARY KEY (sess, key)
);
CREATE FUNCTION var(key varchar, val anyelement) RETURNS void AS $$
  DELETE FROM var WHERE sess = pg_backend_pid() AND key = $1;
  INSERT INTO var (sess, key, val) VALUES (sessid(), $1, $2::varchar);
$$ LANGUAGE 'sql';

CREATE FUNCTION var(varname varchar) RETURNS varchar AS $$
  SELECT val FROM var WHERE sess = pg_backend_pid() AND key = $1;
$$ LANGUAGE 'sql';

Anmerkungen:

  • Plperlu ist schneller als Perl
  • pg_backend_pid ist nicht die beste Sitzungsidentifikation. Erwägen Sie die Verwendung von pid in Kombination mit backend_start von pg_stat_activity
  • Diese Tabellenversion ist auch schlecht, weil Sie sie gelegentlich bereinigen müssen (und nicht die aktuell funktionierenden Sitzungsvariablen löschen müssen).

Variablen in psql saugen.Wenn Sie eine Ganzzahl deklarieren möchten, müssen Sie die Ganzzahl eingeben, dann einen Wagenrücklauf ausführen und die Anweisung dann mit einem Semikolon beenden.Beobachten:

Nehmen wir an, ich möchte eine Ganzzahlvariable deklarieren my_var und fügen Sie es in eine Tabelle ein test:

Beispieltabelle test:

thedatabase=# \d test;
                         Table "public.test"
 Column |  Type   |                     Modifiers                     
--------+---------+---------------------------------------------------
 id     | integer | not null default nextval('test_id_seq'::regclass)
Indexes:
    "test_pkey" PRIMARY KEY, btree (id)

Offensichtlich steht noch nichts in dieser Tabelle:

thedatabase=# select * from test;
 id 
----
(0 rows)

Wir deklarieren eine Variable. Beachten Sie, wie das Semikolon in der nächsten Zeile steht!

thedatabase=# \set my_var 999
thedatabase=# ;

Jetzt können wir einfügen.Wir müssen dieses Seltsame nutzen“:''" suchende Syntax:

thedatabase=# insert into test(id) values (:'my_var');
INSERT 0 1

Es funktionierte!

thedatabase=# select * from test;
 id  
-----
 999
(1 row)

Erläuterung:

Also...Was passiert, wenn wir in der nächsten Zeile kein Semikolon haben?Die Variable?Guck mal:

Wir erklären my_var ohne die neue Zeile.

thedatabase=# \set my_var 999;

Lasst uns auswählen my_var.

thedatabase=# select :'my_var';
 ?column? 
----------
 999;
(1 row)

Was zum Teufel ist das?Es ist kein ganze Zahl, es ist ein Zeichenfolge 999;!

thedatabase=# select 999;
 ?column? 
----------
      999
(1 row)

Ich habe eine neue Lösung dafür gepostet in einem anderen Thread.

Es verwendet eine Tabelle zum Speichern von Variablen und kann jederzeit aktualisiert werden.Eine statische, unveränderliche Getter-Funktion wird dynamisch erstellt (von einer anderen Funktion), ausgelöst durch eine Aktualisierung Ihrer Tabelle.Sie erhalten schönen Tabellenspeicher und die rasend hohen Geschwindigkeiten eines unveränderlichen Getters.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top