PostgreSQL: ¿Cómo pasar parámetros desde la línea de comandos?

92

Tengo una consulta algo detallada en un script que usa ?marcadores de posición. Quería probar esta misma consulta directamente desde la línea de comando psql (fuera del script). Quiero evitar entrar y reemplazar todos los ?valores con valores reales, en su lugar, me gustaría pasar los argumentos después de la consulta.

Ejemplo:

SELECT  * 
FROM    foobar
WHERE   foo = ?
   AND  bar = ?
    OR  baz = ?  ;

Buscando algo como:

%> {select * from foobar where foo=? and bar=? or baz=? , 'foo','bar','baz' };
vol7ron
fuente
Más contexto, por favor. ¿Está esta consulta en un archivo SQL, en un script Perl / Python / Ruby / <inserte el lenguaje de programación favorito aquí> o en algún otro lugar?
@Jack: Estoy buscando hacer esto directamente desde el símbolo del sistema psql (línea de comando). Estoy tomando mi código de un script, pero no quiero pasar por todo el proceso de búsqueda / reemplazo.
vol7ron
@ Vol7ron, consulte mi respuesta a continuación para ver un ejemplo de línea de comando psql.
MAbraham1
1
@ MAbraham1: bueno. Debería haber dado más antecedentes a mi pregunta. Tengo muchos scripts que tienen SQL en texto abierto. A veces es útil tomarlos y golpearlos directamente contra la base de datos, con valores personalizados para depurar. Estaba buscando una manera de hacerlo fácilmente dentro de Postgres sin necesidad de guardar archivos adicionales.
vol7ron
@ Vol7ron, gracias. Estaba pensando en términos de trabajos por lotes, sin embargo, también debería poder usar los tokens en SQL abierto. No olvides votar si te gustó mi respuesta.
MAbraham1

Respuestas:

178

Puede usar la construcción -v, por ejemplo

psql -v v1=12  -v v2="'Hello World'" -v v3="'2010-11-12'"

y luego referirse a las variables en sql como: v1,: v2, etc.

select * from table_1 where id = :v1;

Preste atención a cómo pasamos el valor de cadena / fecha usando dos comillas " '...' "

Gavin
fuente
2
+1 Interesante, pasando argumentos con nombre. ¿Conoce alguna forma de hacer esto una vez que haya iniciado sesión?
vol7ron
9
Claro, solo usa \set v3 'another value'. Solo recuerde, cuando necesite citar el valor en la declaración SQL, use apóstrofos alrededor del nombre de la variable, como este:SELECT * FROM foo WHERE bar = :'v3';
Cromax
1
Supongo que lo sacaron deawk
Neil McGuigan
1
Se puede usar @ en lugar de: como sqlserver
Awais Mahmood
4
Tenga en cuenta que al leer esto, esperaba encontrar que las variables configuradas con -v estarían disponibles para los comandos ejecutados con -c, pero, lamentablemente, no lo están. En otras palabras, psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" -c 'select * from table_1 where id = :v1;' generará un error de sintaxis. Sin embargo, si bash es su shell, puede intentar: psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" <<< 'select * from table_1 where id = :v1;' con buenos resultados.
malcook
30

Descubierto en PostgreSQL, puede hacer PREPAREdeclaraciones como puede hacerlo en un lenguaje de programación. Desafortunadamente, todavía no puede usar ?, pero puede usar la $nnotación.

Usando el ejemplo anterior:

PREPARE foo(text,text,text) AS
    SELECT  * 
    FROM    foobar
    WHERE   foo = $1
       AND  bar = $2
        OR  baz = $3  ;
EXECUTE foo('foo','bar','baz');
DEALLOCATE foo;
vol7ron
fuente
@IvanBlack, ¿había algo más que quisieras incluir con eso? :) la desasignación se realiza automáticamente al final de una sesión
vol7ron
Solo tenga en cuenta que ahora fooestá ocupado y otro PREPAREdebería tener otro nombre mientras la sesión actual no esté cerrada. Si juegas con PREPAREen psql, es difícil inventar cada vez un nuevo nombre y DEALLOCATEpuedes ayudar con él =)
Ivan Black
Gracias por mencionar esto. No he usado PREPARE en algún tiempo, pero esa es información útil
vol7ron
Esta solución es muy buena en mi opinión. Un efecto secundario útil: puede llamar fácilmente a la declaración preparada varias veces.
Yuri
13

En psql hay un mecanismo a través del

\set name val

comando, que se supone que está vinculado al -v name=val opción de la línea de comandos. Citar es doloroso. En la mayoría de los casos, es más fácil poner toda la carne de consulta dentro de un documento shell aquí.

Editar

Ups, debería haber dicho en -vlugar de -P(que es para opciones de formato) la respuesta anterior lo hizo bien.

wildplasser
fuente
7

También puede pasar los parámetros en la línea de comandos psql o desde un archivo por lotes. Las primeras declaraciones recopilan los detalles necesarios para conectarse a su base de datos.

El mensaje final solicita los valores de restricción, que se utilizarán en la cláusula IN () de la columna WHERE. Recuerde poner comillas simples si son cadenas y separarlas por comas:

@echo off
echo "Test for Passing Params to PGSQL"
SET server=localhost
SET /P server="Server [%server%]: "

SET database=amedatamodel
SET /P database="Database [%database%]: "

SET port=5432
SET /P port="Port [%port%]: "

SET username=postgres
SET /P username="Username [%username%]: "

SET /P bunos="Enter multiple constraint values for IN clause [%constraints%]: "
ECHO you typed %constraints%
PAUSE
REM pause
"C:\Program Files\PostgreSQL\9.0\bin\psql.exe" -h %server% -U %username% -d %database% -p %port% -e -v v1=%constraints% -f test.sql

Ahora, en su archivo de código SQL, agregue el token v1 dentro de su cláusula WHERE, o en cualquier otro lugar del SQL. Tenga en cuenta que los tokens también se pueden usar en una declaración SQL abierta, no solo en un archivo. Guarde esto como test.sql:

SELECT * FROM myTable
WHERE NOT someColumn IN (:v1);

En Windows, guarde todo el archivo como un archivo DOS BATch (.bat), guarde test.sql en el mismo directorio y ejecute el archivo batch.

Gracias a Dave Page, de EnterpriseDB, por la secuencia de comandos solicitada original.

MAbraham1
fuente
+1 para el ejemplo de Windows; aunque la mayoría de las bases de datos Pg existen en una variante * nix
vol7ron
2

Parece que lo que pregunta no se puede hacer directamente desde la línea de comandos . Tendrá que usar una función definida por el usuario en plpgsql o llamar a la consulta desde un lenguaje de scripting (y este último enfoque hace que sea un poco más fácil evitar la inyección de SQL).

Comunidad
fuente
¿No fui yo? Muchas veces deseo que los votos negativos requieran algún tipo de explicación (similar a las razones por las que votamos para cerrar las preguntas), incluso si se dejan de forma anónima.
vol7ron