PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Sử dụng đầu ra văn bản từ một hàm làm truy vấn mới

Thủ thuật với PREPARE không hoạt động, vì nó không sử dụng * chuỗi văn bản * (một giá trị) như CREATE FUNCTION không, nhưng một tuyên bố hợp lệ (mã).

Để chuyển đổi dữ liệu thành có thể thực thi bạn cần sử dụng SQL động, tức là EXECUTE trong một hàm plpgsql hoặc DO tuyên bố. Điều này hoạt động mà không có vấn đề gì miễn là kiểu trả về không phụ thuộc vào kết quả của hàm đầu tiên myresult() . Nếu không, bạn sẽ quay lại bắt 22 như đã nêu trong câu trả lời trước của tôi:

  • Cách thực thi một kết quả chuỗi của một thủ tục được lưu trữ trong postgres

Phần quan trọng là khai báo kiểu trả về (loại hàng trong trường hợp này) bằng cách nào đó. Bạn có thể tạo TABLE , TEMP TABLE hoặc TYPE cho mục đích. Hoặc bạn có thể sử dụng một câu lệnh đã chuẩn bị sẵn hoặc một con trỏ chuột.

Giải pháp với tuyên bố đã chuẩn bị sẵn

Bạn đã ở rất gần. Phần còn thiếu của câu đố là chuẩn bị truy vấn được tạo bằng SQL động .

Hàm chuẩn bị động câu lệnh

Tạo chức năng này một lần . Đây là phiên bản được tối ưu hóa và an toàn của hàm myresult() của bạn :

CREATE OR REPLACE FUNCTION f_prep_query (_tbl regclass, _prefix text)
  RETURNS void AS 
$func$
BEGIN
   IF EXISTS (SELECT 1 FROM pg_prepared_statements WHERE name = 'stmt_dyn') THEN
      DEALLOCATE stmt_dyn;
   END IF;                 -- you my or may not need this safety check 

   EXECUTE (
     SELECT 'PREPARE stmt_dyn AS SELECT '
         || string_agg(quote_ident(attname), ',' ORDER BY attname)
         || ' FROM ' || _tbl
      FROM   pg_catalog.pg_attribute
      WHERE  attrelid = _tbl
      AND    attname LIKE _prefix || '%'
      AND    attnum > 0
      AND    NOT attisdropped
     );
END
$func$  LANGUAGE plpgsql;

Tôi sử dụng regclass cho tham số tên bảng _tbl để làm cho nó rõ ràng và an toàn trước SQLi. Chi tiết:

  • Tên bảng dưới dạng tham số hàm PostgreSQL

Lược đồ thông tin không bao gồm cột oid của danh mục hệ thống, vì vậy tôi đã chuyển sang pg_catalog.pg_attribute thay vì information_schema.columns . Nó cũng nhanh hơn. Có những ưu và nhược điểm cho điều này:

  • Cách kiểm tra xem một bảng có tồn tại trong một lược đồ nhất định không

Nếu một câu lệnh chuẩn bị có tên stmt_dyn đã tồn tại, PREPARE sẽ nêu ra một ngoại lệ. Nếu điều đó có thể chấp nhận được, hãy xóa kiểm tra trên chế độ xem hệ thống pg_prepared_statementsDEALLOCATE sau .
Các thuật toán phức tạp hơn có thể quản lý nhiều câu lệnh đã chuẩn bị cho mỗi phiên hoặc lấy tên của câu lệnh đã chuẩn bị làm tham số bổ sung hoặc thậm chí sử dụng hàm băm MD5 của chuỗi truy vấn làm tên, nhưng điều đó vượt quá phạm vi của câu hỏi này.

Lưu ý rằng PREPARE hoạt động ngoài phạm vi giao dịch , một lần PREPARE thành công, câu lệnh đã chuẩn bị tồn tại trong suốt thời gian của phiên. Nếu giao dịch gói bị hủy bỏ, hãy PREPARE không bị ảnh hưởng. ROLLBACK không thể loại bỏ các báo cáo đã chuẩn bị.

Thực thi truy vấn động

Hai truy vấn, nhưng chỉ một gọi đến máy chủ. Và cũng rất hiệu quả.

SELECT f_prep_query('tbl'::regclass, 'pre'::text);
EXECUTE stmt_dyn;

Đơn giản hơn và hiệu quả hơn nhiều cho hầu hết các trường hợp sử dụng đơn giản hơn là tạo bảng tạm thời hoặc con trỏ và chọn / tìm nạp từ đó (sẽ là các tùy chọn khác).

SQL Fiddle.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Hàm xóa dấu trong postgreSQL

  2. Thực hiện thay đổi cấu trúc liên kết sao chép cho PostgreSQL

  3. Cách liệt kê Cơ sở dữ liệu và Bảng trong PostgreSQL bằng psql

  4. Hướng dẫn về PGpool - Gợi ý &Quan sát:Phần ba

  5. MigrationSchemaMissing (Không thể tạo bảng django_migrations (% s)% exc)