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

Làm cách nào để bạn có được chế độ xem 12 ngày làm việc năng động trong Postgresql?

Điều này có thể được giải quyết bằng CTE:

WITH business_days_back AS (
  WITH RECURSIVE bd(back_day, go_back) AS (
    -- Go back to the previous Monday, allowing for current_date in the weekend
    SELECT CASE extract(dow from current_date)
             WHEN 0 THEN current_date - 6
             WHEN 6 THEN current_date - 5
             ELSE current_date - extract(dow from current_date)::int + 1
           END,
           CASE extract(dow from current_date)
             WHEN 0 THEN 7
             WHEN 6 THEN 7
             ELSE 12 - extract(dow from current_date)::int + 1
           END
    UNION
    -- Go back by the week until go_back = 0
    SELECT CASE
         WHEN go_back >= 5 THEN back_day - 7
         WHEN go_back > 0 THEN back_day - 2 - go_back
       END,
       CASE
         WHEN go_back >= 5 THEN go_back - 5
         WHEN go_back > 0 THEN 0
       END
    FROM bd
  )
  SELECT back_day FROM bd WHERE go_back = 0
)
SELECT * FROM my_table WHERE analysis_date >= (SELECT * FROM business_days_back);

Một số giải thích:

  • CTE bên trong bắt đầu bằng cách hoạt động trở lại Thứ Hai trước đó, bù đắp cho một current_date rơi vào một ngày cuối tuần.
  • Sau đó, thuật ngữ đệ quy sẽ thêm các hàng bằng cách quay lại các tuần đầy đủ (back_day - 7 cho ngày lịch và go_back - 5 trong ngày làm việc) cho đến khi go_back = 0 .
  • CTE bên ngoài trả về back_day ngày mà go_back = 0 . Do đó, đây là một truy vấn vô hướng và bạn có thể sử dụng nó như một truy vấn phụ trong một biểu thức bộ lọc.

Bạn có thể thay đổi số ngày làm việc để xem lại bằng cách chỉ cần thay đổi các số 127 trong SELECT ban đầu trong CTE bên trong. Tuy nhiên, hãy nhớ rằng giá trị phải sao cho nó quay trở lại thứ Hai trước đó, nếu không truy vấn sẽ không thành công, do cùng một SELECT ban đầu của CTE bên trong.

Một giải pháp linh hoạt hơn nhiều (và có lẽ nhanh hơn *) là sử dụng hàm sau:

CREATE FUNCTION business_days_diff(from_date date, diff int) RETURNS date AS $$
-- This function assumes Mon-Fri business days
DECLARE
  start_dow int;
  calc_date date;
  curr_diff int;
  weekend   int;
BEGIN
  -- If no diff requested, return the from_date. This may be a non-business day.
  IF diff = 0 THEN
    RETURN from_date;
  END IF;

  start_dow := extract(dow from from_date)::int;
  calc_date := from_date;

  IF diff < 0 THEN -- working backwards
    weekend := -2;
    IF start_dow = 0 THEN -- Fudge initial Sunday to the previous Saturday
      calc_date := calc_date - 1;
      start_dow := 6;
    END IF;
    IF start_dow + diff >= 1 THEN -- Stay in this week
      RETURN calc_date + diff;
    ELSE                             -- Work back to Monday
      calc_date := calc_date - start_dow + 1;
      curr_diff := diff + start_dow - 1;
    END IF;
  ELSE -- Working forwards
    weekend := 2;
    IF start_dow = 6 THEN -- Fudge initial Saturday to the following Sunday
      calc_date := calc_date + 1;
      start_dow := 0;
    END IF;
    IF start_dow + diff <= 5 THEN -- Stay in this week
      RETURN calc_date + diff;
    ELSE                             -- Work forwards to Friday
      calc_date := calc_date + 5 - start_dow;
      curr_diff := diff - 5 + start_dow;
    END IF;
  END IF;

  -- Move backwards or forwards by full weeks
  calc_date := calc_date + (curr_diff / 5) * 7;

  -- Process any remaining days, include weekend
  IF curr_diff % 5 != 0 THEN
    RETURN calc_date + curr_diff % 5 + weekend;
  ELSE
    RETURN calc_date;
  END IF;
END; $$ LANGUAGE plpgsql STRICT IMMUTABLE;

Hàm này có thể lấy bất kỳ ngày nào để tính toán từ đó và bất kỳ số ngày nào trong tương lai (giá trị dương của diff ) hoặc quá khứ (giá trị âm của diff ), bao gồm các khác biệt trong tuần hiện tại. Và vì nó trả về ngày của ngày làm việc dưới dạng một đại lượng vô hướng, việc sử dụng trong truy vấn của bạn rất đơn giản:

SELECT * 
FROM table
WHERE analysis_date >= business_days_diff(current_date, -12);

Ngoài ra, bạn cũng có thể chuyển vào các trường từ bảng của mình và làm những điều thú vị như:

SELECT t1.some_value - t2.some_value AS value_diff
FROM table t1
JOIN table t2 ON t2.analysis_date = business_days_diff(t1.analysis_date, -12);

tức là tự tham gia vào một số ngày làm việc riêng biệt.

Lưu ý rằng hàm này giả định là ngày làm việc từ Thứ Hai đến Thứ Sáu trong tuần.

* Hàm này chỉ thực hiện số học đơn giản trên các giá trị vô hướng. CTE phải thiết lập tất cả các cách cấu trúc để hỗ trợ quá trình lặp lại và các tập hợp bản ghi kết quả.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để thực hiện việc hút chân không bằng PostgreSQL?

  2. Đối số tùy chọn trong hàm PL / pgSQL

  3. Làm thế nào để sử dụng ilike sqlalchemy trên trường mảng postgresql?

  4. Làm cách nào để tôi có thể lắng nghe việc tạo ra một mô hình cụ thể và tạo một mô hình mới (trên một bảng khác) dựa trên điều này?

  5. Truy vấn đường ray (postgres) với mảng jsonb