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

Kiểm tra hàm null với các tham số khác nhau

Tôi không đồng ý với một số lời khuyên trong các câu trả lời khác. Điều này có thể được thực hiện với PL / pgSQL và tôi nghĩ rằng nó hầu hết vượt trội hơn nhiều để tập hợp các truy vấn trong một ứng dụng khách. Nó nhanh hơn và sạch hơn và ứng dụng chỉ gửi mức tối thiểu qua đường dây trong các yêu cầu. Các câu lệnh SQL được lưu bên trong cơ sở dữ liệu, giúp dễ bảo trì hơn - trừ khi bạn muốn thu thập tất cả logic nghiệp vụ trong ứng dụng khách, điều này phụ thuộc vào kiến ​​trúc chung.

Hàm PL / pgSQL với SQL động

CREATE OR REPLACE FUNCTION func(
      _ad_nr       int  = NULL
    , _ad_nr_extra text = NULL
    , _ad_info     text = NULL
    , _ad_postcode text = NULL
    , _sname       text = NULL
    , _pname       text = NULL
    , _cname       text = NULL)
  RETURNS TABLE(id int, match text, score int, nr int, nr_extra text
              , info text, postcode text, street text, place text
              , country text, the_geom geometry)
  LANGUAGE plpgsql AS
$func$
BEGIN
   -- RAISE NOTICE '%', -- for debugging
   RETURN QUERY EXECUTE concat(
   $$SELECT a.id, 'address'::text, 1 AS score, a.ad_nr, a.ad_nr_extra
        , a.ad_info, a.ad_postcode$$

   , CASE WHEN (_sname, _pname, _cname) IS NULL THEN ', NULL::text' ELSE ', s.name' END  -- street
   , CASE WHEN (_pname, _cname) IS NULL         THEN ', NULL::text' ELSE ', p.name' END  -- place
   , CASE WHEN _cname IS NULL                   THEN ', NULL::text' ELSE ', c.name' END  -- country
   , ', a.wkb_geometry'

   , concat_ws('
   JOIN   '
   , '
   FROM   "Addresses" a'
   , CASE WHEN NOT (_sname, _pname, _cname) IS NULL THEN '"Streets"   s ON s.id = a.street_id' END
   , CASE WHEN NOT (_pname, _cname) IS NULL         THEN '"Places"    p ON p.id = s.place_id' END
   , CASE WHEN _cname IS NOT NULL                   THEN '"Countries" c ON c.id = p.country_id' END
   )

   , concat_ws('
   AND    '
      , '
   WHERE  TRUE'
      , CASE WHEN $1 IS NOT NULL THEN 'a.ad_nr = $1' END
      , CASE WHEN $2 IS NOT NULL THEN 'a.ad_nr_extra = $2' END
      , CASE WHEN $3 IS NOT NULL THEN 'a.ad_info = $3' END
      , CASE WHEN $4 IS NOT NULL THEN 'a.ad_postcode = $4' END
      , CASE WHEN $5 IS NOT NULL THEN 's.name = $5' END
      , CASE WHEN $6 IS NOT NULL THEN 'p.name = $6' END
      , CASE WHEN $7 IS NOT NULL THEN 'c.name = $7' END
   )
   )
   USING $1, $2, $3, $4, $5, $6, $7;
END
$func$;

Gọi:

SELECT * FROM func(1, '_ad_nr_extra', '_ad_info', '_ad_postcode', '_sname');

SELECT * FROM func(1, _pname := 'foo');

Vì tất cả các tham số hàm đều có giá trị mặc định, bạn có thể sử dụng vị trí ký hiệu, được đặt tên ký hiệu hoặc hỗn hợp ký hiệu bạn chọn trong lệnh gọi hàm. Xem:

  • Các hàm có số lượng tham số đầu vào thay đổi

Giải thích thêm về những điều cơ bản về SQL động:

  • Cấu trúc lại một hàm PL / pgSQL để trả về kết quả đầu ra của các truy vấn SELECT khác nhau

concat() chức năng là công cụ để xây dựng chuỗi. Nó được giới thiệu với Postgres 9.1.

ELSE nhánh của CASE câu lệnh mặc định là NULL khi không có mặt. Đơn giản hóa mã.

USING mệnh đề cho EXECUTE làm cho việc đưa vào SQL không thể thực hiện được vì các giá trị được truyền dưới dạng giá trị và cho phép sử dụng trực tiếp các giá trị tham số, giống như trong các câu lệnh đã chuẩn bị.

NULL giá trị được sử dụng để bỏ qua các tham số ở đây. Chúng không thực sự được sử dụng để tìm kiếm.

Bạn không cần dấu ngoặc đơn xung quanh SELECT với RETURN QUERY .

Hàm SQL đơn giản

Bạn có thể làm điều đó với một hàm SQL thuần túy và tránh SQL động. Đối với một số trường hợp, điều này có thể nhanh hơn. Nhưng tôi sẽ không mong đợi điều đó trong trường hợp này . Lập kế hoạch truy vấn mà không có các phép nối và vị từ không cần thiết thường tạo ra kết quả tốt nhất. Lập kế hoạch chi phí cho một truy vấn đơn giản như thế này hầu như không đáng kể.

CREATE OR REPLACE FUNCTION func_sql(
     _ad_nr       int  = NULL
   , _ad_nr_extra text = NULL
   , _ad_info     text = NULL
   , _ad_postcode text = NULL
   , _sname       text = NULL
   , _pname       text = NULL
   , _cname       text = NULL)
  RETURNS TABLE(id int, match text, score int, nr int, nr_extra text
              , info text, postcode text, street text, place text
              , country text, the_geom geometry)
  LANGUAGE sql AS 
$func$
SELECT a.id, 'address' AS match, 1 AS score, a.ad_nr, a.ad_nr_extra
     , a.ad_info, a.ad_postcode
     , s.name AS street, p.name AS place
     , c.name AS country, a.wkb_geometry
FROM   "Addresses"      a
LEFT   JOIN "Streets"   s ON s.id = a.street_id
LEFT   JOIN "Places"    p ON p.id = s.place_id
LEFT   JOIN "Countries" c ON c.id = p.country_id
WHERE ($1 IS NULL OR a.ad_nr = $1)
AND   ($2 IS NULL OR a.ad_nr_extra = $2)
AND   ($3 IS NULL OR a.ad_info = $3)
AND   ($4 IS NULL OR a.ad_postcode = $4)
AND   ($5 IS NULL OR s.name = $5)
AND   ($6 IS NULL OR p.name = $6)
AND   ($7 IS NULL OR c.name = $7)
$func$;

Cuộc gọi giống hệt nhau.

Để bỏ qua các tham số một cách hiệu quả với NULL giá trị :

($1 IS NULL OR a.ad_nr = $1)

Để thực sự sử dụng giá trị NULL làm tham số , hãy sử dụng cấu trúc này thay thế:

($1 IS NULL AND a.ad_nr IS NULL OR a.ad_nr = $1)  -- AND binds before OR

Điều này cũng cho phép lập chỉ mục sẽ được sử dụng.
Đối với trường hợp hiện tại, hãy thay thế tất cả các bản sao của LEFT JOIN với JOIN .

db <> fiddle here - với bản trình diễn đơn giản cho tất cả các biến thể.
sqlfiddle cũ

Bên cạnh

  • Không sử dụng nameid dưới dạng tên cột. Chúng không mang tính mô tả và khi bạn tham gia nhiều bảng (giống như bạn làm với a lot trong cơ sở dữ liệu quan hệ), bạn kết thúc với một số cột có tên là name hoặc id và phải đính kèm các bí danh để sắp xếp lộn xộn.

  • Vui lòng định dạng SQL của bạn đúng cách, ít nhất là khi đặt câu hỏi công khai. Nhưng hãy làm điều đó một cách riêng tư, vì lợi ích của riêng bạn.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách thêm số ngày trong datetime postgresql

  2. Cách kết nối với máy chủ PostgreSQL từ máy ảo vagrant

  3. Xu hướng PostgreSQL mới nhất:Các công việc tiêu tốn nhiều thời gian nhất &các chỉ số quan trọng cần theo dõi

  4. làm thế nào để đặt tiền tố một chuỗi trước chuỗi được tạo bởi postgresql?

  5. Tạo bảng tổng hợp với PostgreSQL