PostgreSQL: как передать параметры из командной строки?

95

У меня есть несколько подробный запрос в скрипте, который использует ?заполнители. Я хотел протестировать этот же запрос непосредственно из командной строки psql (вне сценария). Я хочу избежать замены всех ?фактических значений, вместо этого я хотел бы передать аргументы после запроса.

Пример:

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

Ищу что-то вроде:

%> {select * from foobar where foo=? and bar=? or baz=? , 'foo','bar','baz' };
vol7ron
источник
Больше контекста, пожалуйста. Находится ли этот запрос в файле SQL, в сценарии Perl / Python / Ruby / <вставьте здесь любимый язык сценариев> или в другом месте?
@Jack: Я хочу сделать это прямо из командной строки psql. Я беру свой код из скрипта, но не хочу проходить весь процесс поиска / замены.
vol7ron
@ Vol7ron, см. Мой ответ ниже для примера командной строки psql.
MAbraham1
1
@ MAbraham1: хорошо. Я должен был дать более подробную информацию о моем вопросе. У меня много скриптов с открытым текстом SQL. Иногда бывает полезно взять их и применить непосредственно к базе данных с настраиваемыми значениями для отладки. Я искал способ легко сделать это внутри Postgres без необходимости сохранять дополнительные файлы.
vol7ron
@ Vol7ron, спасибо. Я думал о пакетных заданиях, однако вы также должны иметь возможность использовать токены в открытом SQL. Не забудьте проголосовать, если вам понравился мой ответ.
MAbraham1

Ответы:

181

Вы можете использовать конструкцию -v, например

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

а затем ссылаться на переменные в sql как: v1,: v2 и т. д.

select * from table_1 where id = :v1;

Обратите внимание, как мы передаем значение строки / даты, используя две кавычки " '...' "

Гэвин
источник
2
+1 Интересно прохождение именованных аргументов. Знаете ли вы, как это сделать после входа в систему?
vol7ron
9
Конечно, просто используйте \set v3 'another value'. Просто помните, когда вам нужно SELECT * FROM foo WHERE bar = :'v3';
заключить
2
Я предполагаю , что они получили , что изawk
Нил МакГигана
1
Может @ использоваться вместо: например, sqlserver
Авайс Махмуд
5
Обратите внимание: прочитав это, я надеялся обнаружить, что переменные, установленные с помощью -v, будут доступны для команд, выполняемых с -c, но, увы, это не так. Другими словами, psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" -c 'select * from table_1 where id = :v1;' сгенерирует синтаксическую ошибку. Однако, если вашей оболочкой является bash, вы можете попробовать: psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" <<< 'select * from table_1 where id = :v1;' с хорошим эффектом.
malcook
31

Как выяснилось в PostgreSQL, вы можете использовать PREPAREоператоры так же, как и в языке сценариев. К сожалению, вы все еще не можете использовать ?, но можете использовать $nобозначения.

Используя приведенный выше пример:

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
источник
@IvanBlack Вы хотели добавить сюда еще что-нибудь? :) освобождение происходит автоматически в конце сеанса
vol7ron
Просто обратите внимание, что сейчас fooон занят, а другой PREPAREдолжен иметь другое имя, пока текущий сеанс не закрыт. Если вы играете с PREPAREв psqlэто трудно придумать каждый раз новое имя и DEALLOCATEможет помочь с этим =)
Иван Черный
Спасибо, что упомянули об этом. Я не использовал PREPARE какое-то время, но это полезная информация
vol7ron
Это решение IMO очень хорошее. Полезный побочный эффект - вы можете легко вызвать подготовленный оператор несколько раз.
Юрий
14

В psql есть механизм через

\set name val

команда, которая должна быть связана с параметром -v name=valкомандной строки. Цитирование болезненно. В большинстве случаев проще поместить все содержание запроса в оболочку here-document.

редактировать

ой, я должен был сказать -vвместо -P(что касается параметров форматирования) предыдущий ответ все правильно.

Wildplasser
источник
7

Вы также можете передать параметры в командной строке psql или из командного файла. Первые операторы собирают необходимые данные для подключения к вашей базе данных.

Последнее приглашение запрашивает значения ограничений, которые будут использоваться в предложении WHERE column IN (). Не забудьте заключать строки в одинарные кавычки и разделять их запятыми:

@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

Теперь в вашем файле кода SQL добавьте токен v1 в предложение WHERE или где-нибудь еще в SQL. Обратите внимание, что токены также могут использоваться в открытом операторе SQL, а не только в файле. Сохраните это как test.sql:

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

В Windows сохраните весь файл как пакетный файл DOS (.bat), сохраните test.sql в том же каталоге и запустите пакетный файл.

Спасибо Дэйву Пейджу из EnterpriseDB за оригинальный сценарий с подсказками.

оборота MAbraham1
источник
+1 для примера Windows; хотя большинство баз данных Pg существуют в варианте * nix
vol7ron
2

Казалось бы, то, что вы просите, нельзя сделать прямо из командной строки . Вам придется либо использовать определяемую пользователем функцию в plpgsql, либо вызывать запрос из языка сценариев (и последний подход немного упрощает предотвращение внедрения SQL).

Сообщество
источник
Был не я - много раз я хотел, чтобы голоса против требовали какого-то объяснения (аналогично причинам, по которым мы голосуем за закрытые вопросы), даже если они оставлены анонимно.
vol7ron
0

Я хотел бы предложить другой ответ, вдохновленный комментарием @ malcook (с использованием bash).

Эта опция может работать для вас, если вам нужно использовать переменные оболочки в вашем запросе при использовании -cфлага . В частности, я хотел получить счетчик таблицы, имя которой было переменной оболочки (которую вы не можете передать напрямую при использовании -c).

Предположим, у вас есть переменная оболочки

$TABLE_NAME='users'

Затем вы можете получить результаты, используя

psql -q -A -t -d databasename -c <<< echo "select count(*) from $TABLE_NAME;"

( -q -A -tпросто распечатать получившееся число без дополнительного форматирования)

Замечу, что echoв строке здесь ( <<<оператор) может не быть необходимости, я изначально думал, что цитаты сами по себе подойдут, может быть, кто-то сможет прояснить причину этого.

Бропер
источник
0

В итоге я использовал лучшую версию ответа @ vol7ron:

DO $$
BEGIN
    IF NOT EXISTS(SELECT 1 FROM pg_prepared_statements WHERE name = 'foo') THEN
        PREPARE foo(text,text,text) AS
            SELECT  * 
            FROM    foobar
            WHERE   foo = $1
                AND bar = $2
                OR  baz = $3;
    END IF;
END$$;
EXECUTE foo('foo','bar','baz');

Таким образом, вы всегда можете выполнить его в таком порядке (запрос подготовлен, только если он еще не подготовлен), повторить выполнение и получить результат последнего запроса.

Конард
источник