PostgreSQL: Làm thế nào để chuyển các tham số từ dòng lệnh?


92

Tôi có một truy vấn hơi chi tiết trong một tập lệnh sử dụng ?trình giữ chỗ. Tôi muốn kiểm tra cùng một truy vấn này trực tiếp từ dòng lệnh psql (bên ngoài tập lệnh). Tôi muốn tránh đi vào và thay thế tất cả các ?giá trị thực, thay vào đó tôi muốn chuyển các đối số sau truy vấn.

Thí dụ:

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

Tìm kiếm một cái gì đó như:

%> {select * from foobar where foo=? and bar=? or baz=? , 'foo','bar','baz' };

Thêm ngữ cảnh, làm ơn. Truy vấn này nằm trong một tệp SQL, trong tập lệnh Perl / Python / Ruby / <chèn ngôn ngữ kịch bản yêu thích tại đây> hay ở một số nơi khác?

@Jack: Tôi đang tìm cách thực hiện việc này trực tiếp từ dấu nhắc psql (dòng lệnh). Tôi đang lấy mã của mình từ một tập lệnh, nhưng không muốn thực hiện toàn bộ quá trình tìm / thay thế.
vol7ron

@ Vol7ron, vui lòng xem câu trả lời của tôi bên dưới để biết ví dụ về dòng lệnh psql.
MAbraham1

1
@ MAbraham1: hay quá. Tôi nên cung cấp thêm một số thông tin cơ bản cho câu hỏi của mình. Tôi có rất nhiều tập lệnh có SQL trong văn bản mở. Đôi khi, rất hữu ích khi lấy những thứ đó và đánh những thứ đó trực tiếp vào cơ sở dữ liệu, với các giá trị tùy chỉnh để gỡ lỗi. Tôi đang tìm một cách để dễ dàng thực hiện việc đó bên trong Postgres mà không cần lưu các tệp bổ sung.
vol7ron

@ Vol7ron, cảm ơn. Tôi đã suy nghĩ về các công việc hàng loạt, tuy nhiên bạn cũng có thể sử dụng các mã thông báo trong SQL mở. Đừng quên bình chọn nếu bạn thích câu trả lời của tôi.
MAbraham1

Câu trả lời:


178

Bạn có thể sử dụng cấu trúc -v, ví dụ:

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

và sau đó tham chiếu đến các biến trong sql như: v1,: v2, v.v.

select * from table_1 where id = :v1;

Hãy chú ý đến cách chúng tôi chuyển giá trị chuỗi / ngày bằng hai dấu ngoặc kép " '...' "


2
+1 Thú vị, chuyển các đối số được đặt tên. Bạn có biết cách nào để thực hiện việc này sau khi đăng nhập không?
vol7ron

9
Chắc chắn, chỉ cần sử dụng \set v3 'another value'. Chỉ cần nhớ, khi bạn cần phải trích dẫn giá trị trong câu lệnh SQL, sử dụng dấu nháy tên xung quanh thay đổi, như thế này:SELECT * FROM foo WHERE bar = :'v3';
Cromax

1
Tôi đoán họ nhận được điều đó từawk
Neil McGuigan.

1
@ Có thể được sử dụng thay cho: như SQLServer
Awais Mahmood

4
Lưu ý, khi đọc phần này, tôi hy vọng sẽ thấy rằng các biến được đặt với -v sẽ khả dụng cho các lệnh được thực hiện với -c, nhưng, than ôi là không. Nói cách khác, psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" -c 'select * from table_1 where id = :v1;' sẽ tạo ra một lỗi cú pháp. Tuy nhiên, nếu bash là vỏ của bạn, bạn có thể thử: psql -v v1=12 -v v2="'Hello World'" -v v3="'2010-11-12'" <<< 'select * from table_1 where id = :v1;' để có hiệu quả tốt.
malcook

30

Được tìm thấy trong PostgreSQL, bạn có thể PREPAREphát biểu giống như bạn có thể làm trong một ngôn ngữ kịch bản. Thật không may, bạn vẫn không thể sử dụng ?, nhưng bạn có thể sử dụng $nký hiệu.

Sử dụng ví dụ trê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;

@IvanBlack có điều gì khác mà bạn muốn đưa vào cùng không? :) thỏa thuận phân bổ được tự động thực hiện vào cuối phiên
vol7ron

Chỉ cần lưu ý rằng bây giờ phiên foođang bận và một phiên khác PREPAREsẽ có tên khác trong khi phiên hiện tại chưa đóng. Nếu bạn chơi với PREPAREthành psqlthật khó để phát minh ra mỗi lần một tên mới và DEALLOCATEcó thể giúp với nó =)
Ivan Đen

Cảm ơn vì đã đề cập đến điều này. Tôi đã không được sử dụng CHUẨN BỊ trong một thời gian, nhưng đó là thông tin hữu ích
vol7ron

Giải pháp này là IMO rất tốt. Một tác dụng phụ hữu ích - bạn có thể dễ dàng gọi câu lệnh đã chuẩn bị nhiều lần.
Yuri

13

Trong psql có một cơ chế thông qua

\set name val

lệnh, được cho là gắn với -v name=valtùy chọn dòng lệnh. Trích dẫn rất khó, Trong hầu hết các trường hợp, việc đặt toàn bộ câu hỏi bên trong một shell tại đây sẽ dễ dàng hơn.

Biên tập

oops, tôi nên nói -vthay vì -P(dành cho các tùy chọn định dạng) câu trả lời trước đó đã đúng.


7

Bạn cũng có thể chuyển các tham số vào dòng lệnh psql hoặc từ một tệp loạt. Các câu lệnh đầu tiên thu thập các chi tiết cần thiết để kết nối với cơ sở dữ liệu của bạn.

Lời nhắc cuối cùng yêu cầu các giá trị ràng buộc, giá trị này sẽ được sử dụng trong mệnh đề IN () cột WHERE. Hãy nhớ trích dẫn một chuỗi if và phân tách bằng dấu phẩy:

@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

Bây giờ trong tệp mã SQL của bạn, hãy thêm mã thông báo v1 trong mệnh đề WHERE của bạn hoặc bất kỳ nơi nào khác trong SQL. Lưu ý rằng các mã thông báo cũng có thể được sử dụng trong một câu lệnh SQL mở, không chỉ trong một tệp. Lưu nó dưới dạng test.sql:

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

Trong Windows, lưu toàn bộ tệp dưới dạng tệp DOS BATch (.bat), lưu test.sql trong cùng một thư mục và khởi chạy tệp loạt.

Cảm ơn Dave Page, của EnterpriseDB, vì tập lệnh được nhắc ban đầu.


+1 cho ví dụ Windows; mặc dù hầu hết các cơ sở dữ liệu Thạc tồn tại trong một * nix biến
vol7ron

2

Có vẻ như những gì bạn yêu cầu không thể được thực hiện trực tiếp từ dòng lệnh . Bạn sẽ phải sử dụng một hàm do người dùng định nghĩa trong plpgsql hoặc gọi truy vấn từ một ngôn ngữ kịch bản (và cách tiếp cận thứ hai giúp tránh việc chèn SQL dễ dàng hơn một chút).


Không phải là tôi - nhiều lần tôi ước rằng phiếu phản đối nên yêu cầu một số loại giải thích (tương tự như lý do tại sao chúng tôi bỏ phiếu để đóng câu hỏi), ngay cả khi được giấu tên.
vol7ron
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.