PostgreSQL: Como passar parâmetros da linha de comando?

92

Eu tenho uma consulta um tanto detalhada em um script que usa ?espaços reservados. Eu queria testar essa mesma consulta diretamente da linha de comando do psql (fora do script). Quero evitar entrar e substituir todos os ?por valores reais, em vez disso, gostaria de passar os argumentos após a consulta.

Exemplo:

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

Procurando por algo como:

%> {select * from foobar where foo=? and bar=? or baz=? , 'foo','bar','baz' };
Vol7ron
fonte
Mais contexto, por favor. Esta consulta está em um arquivo SQL, em um script Perl / Python / Ruby / <insira a linguagem de script favorita aqui> ou em algum outro lugar?
@Jack: Estou tentando fazer isso diretamente do prompt do psql (linha de comando). Estou pegando meu código de um script, mas não quero passar por todo o processo de localizar / substituir.
vol7ron
@ Vol7ron, veja minha resposta abaixo para um exemplo de linha de comando do psql.
MAbraham1
1
@ MAbraham1: legal. Eu deveria ter dado mais algumas informações básicas para minha pergunta. Tenho muitos scripts que possuem SQL em texto aberto. Às vezes, é útil pegá-los e acertá-los diretamente no banco de dados, com valores personalizados para depuração. Eu estava procurando uma maneira de fazer isso facilmente dentro do Postgres sem precisar salvar arquivos adicionais.
Vol7ron
@ Vol7ron, obrigado. Eu estava pensando em termos de trabalhos em lote, mas você também deve ser capaz de usar os tokens no SQL aberto. Não se esqueça de votar se gostou da minha resposta.
MAbraham1

Respostas:

178

Você pode usar a construção -v, por exemplo

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

e, em seguida, referir-se às variáveis ​​em sql como: v1,: v2 etc

select * from table_1 where id = :v1;

Preste atenção em como passamos o valor da string / data usando duas aspas " '...' "

Gavin
fonte
2
+1 Interessante, passando argumentos nomeados. Você conhece alguma maneira de fazer isso depois de logado?
vol7ron
9
Claro, apenas use \set v3 'another value'. Apenas lembre-se, quando você precisar citar o valor na instrução SQL, use apóstrofos ao redor do nome da variável, como este:SELECT * FROM foo WHERE bar = :'v3';
Cromax
1
Acho que conseguiram isso deawk
Neil McGuigan,
1
Pode ser usado em vez de: like sqlserver
Awais Mahmood
4
Observe, ao ler isso, eu esperava descobrir que variáveis ​​definidas com -v estariam disponíveis para comandos executados com -c, mas, infelizmente, não estão. Em outras palavras, psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" -c 'select * from table_1 where id = :v1;' gerará um erro de sintaxe. No entanto, se bash é o seu shell, você pode tentar: psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" <<< 'select * from table_1 where id = :v1;' com bons resultados.
malcook
30

Encontrado no PostgreSQL, você pode fazer PREPAREdeclarações exatamente como em uma linguagem de script. Infelizmente, você ainda não pode usar ?, mas pode usar $nnotação.

Usando o exemplo acima:

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
fonte
@IvanBlack havia algo mais que você pretendia incluir com isso? :) a desalocação é realizada automaticamente no final de uma sessão
vol7ron
Observe que agora o fooestá ocupado e outro PREPAREdeve ter outro nome enquanto a sessão atual não estiver fechada. Se você jogar com PREPAREem psqlque é difícil inventar cada vez que um novo nome e DEALLOCATEpode ajudar com isso =)
Ivan Preto
Obrigado por mencionar isso. Eu não uso o PREPARE há algum tempo, mas essa é uma informação útil
vol7ron
Esta solução IMO é muito boa. Um efeito colateral útil - você pode facilmente chamar a instrução preparada várias vezes.
Yuri
13

No psql, há um mecanismo por meio do

\set name val

comando, que deve estar vinculado à -v name=valopção de linha de comando. Citar é doloroso. Na maioria dos casos, é mais fácil colocar toda a carne da consulta dentro de um shell here-document.

Editar

opa, eu deveria ter dito em -vvez de -P(que é para opções de formatação) a resposta anterior acertou.

Wildplasser
fonte
7

Você também pode passar os parâmetros na linha de comando do psql ou de um arquivo em lote. As primeiras instruções reúnem os detalhes necessários para se conectar ao seu banco de dados.

O prompt final pede os valores de restrição, que serão usados ​​na cláusula IN () da coluna WHERE. Lembre-se de colocar aspas simples nas strings e separar por vírgula:

@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

Agora, em seu arquivo de código SQL, adicione o token v1 dentro de sua cláusula WHERE ou em qualquer outro lugar no SQL. Observe que os tokens também podem ser usados ​​em uma instrução SQL aberta, não apenas em um arquivo. Salve como test.sql:

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

No Windows, salve o arquivo inteiro como um arquivo DOS BATch (.bat), salve o test.sql no mesmo diretório e execute o arquivo em lote.

Obrigado por Dave Page, de EnterpriseDB, pelo script original solicitado.

MAbraham1
fonte
+1 para o exemplo do Windows; embora a maioria dos bancos de dados Pg existam em uma variante * nix
vol7ron
2

Parece que o que você pergunta não pode ser feito diretamente da linha de comando . Você terá que usar uma função definida pelo usuário em plpgsql ou chamar a consulta de uma linguagem de script (e a última abordagem torna um pouco mais fácil evitar a injeção de SQL).

Comunidade
fonte
Não fui eu - muitas vezes gostaria que os votos negativos exigissem algum tipo de explicação (semelhante às razões pelas quais votamos para encerrar as questões), mesmo que deixada anonimamente.
vol7ron