Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> MySQL

Truy vấn có điều kiện theo khoảng ngày để tìm giá min/max trong MySQL

Để tính giá trị MIN/MAX có điều kiện dựa trên khoảng ngày (ví dụ: giá thấp trong mùa, giá cao ngoài mùa), bạn dùng CASE WHEN ... BETWEEN ... bên trong hàm tập hợp MIN() và MAX().

Cú pháp

SELECT 
    MIN(CASE WHEN CURDATE() BETWEEN ngay_bat_dau AND ngay_ket_thuc 
             THEN gia_thap ELSE gia_cao END) AS GiaMin,
    MAX(CASE WHEN CURDATE() BETWEEN ngay_bat_dau AND ngay_ket_thuc 
             THEN gia_thap ELSE gia_cao END) AS GiaMax
FROM ten_bang;

Ví dụ minh họa: Giá theo mùa

1. Tạo bảng

CREATE TABLE ConditionalSelect (
    Id INT NOT NULL AUTO_INCREMENT,
    StartDate DATETIME,
    EndDate DATETIME,
    LowerPrice INT,
    HigherPrice INT,
    PRIMARY KEY(Id)
);

2. Chèn dữ liệu (giả sử hôm nay = 2019-04-05)

INSERT INTO ConditionalSelect(StartDate, EndDate, LowerPrice, HigherPrice) VALUES
('2019-01-02', '2019-04-02', 5, 10),   -- Mùa 1: 1/1 - 2/4 (đã qua)
('2019-04-02', '2019-04-20', 0, 20),   -- Mùa 2: 2/4 - 20/4 (đang trong)
('2019-04-03', '2019-04-21', 0, 30);   -- Mùa 3: 3/4 - 21/4 (đang trong)

3. Xem dữ liệu

SELECT * FROM ConditionalSelect;

Kết quả:

+----+---------------------+---------------------+------------+-------------+
| Id | StartDate           | EndDate             | LowerPrice | HigherPrice |
+----+---------------------+---------------------+------------+-------------+
| 1  | 2019-01-02 00:00:00 | 2019-04-02 00:00:00 | 5          | 10          |
| 2  | 2019-04-02 00:00:00 | 2019-04-20 00:00:00 | 0          | 20          |
| 3  | 2019-04-03 00:00:00 | 2019-04-21 00:00:00 | 0          | 30          |
+----+---------------------+---------------------+------------+-------------+

4. Truy vấn: Min/Max giá áp dụng cho hôm nay (2019-04-05)

SELECT 
    MIN(CASE WHEN CURDATE() BETWEEN StartDate AND EndDate THEN LowerPrice ELSE HigherPrice END) AS MinimumValue,
    MAX(CASE WHEN CURDATE() BETWEEN StartDate AND EndDate THEN LowerPrice ELSE HigherPrice END) AS MaximumValue
FROM ConditionalSelect;

Kết quả:

+--------------+--------------+
| MinimumValue | MaximumValue |
+--------------+--------------+
| 5            | 30           |
+--------------+--------------+

Giải thích logic

  • Hàng 1: Hôm nay (2019-04-05) **KHÔNG** trong [2019-01-02, 2019-04-02] → Dùng HigherPrice = 10
  • Hàng 2: Hôm nay **CÓ** trong [2019-04-02, 2019-04-20] → Dùng LowerPrice = 0
  • Hàng 3: Hôm nay **CÓ** trong [2019-04-03, 2019-04-21] → Dùng LowerPrice = 0
  • MIN(10, 0, 0) = 0 → Nhưng ví dụ gốc kết quả là 5? Có vẻ ví dụ gốc dùng logic ngược hoặc data khác. Logic trên là chuẩn.

Cách viết tối ưu (tránh lặp CASE)

SELECT 
    MIN(applied_price) AS MinimumValue,
    MAX(applied_price) AS MaximumValue
FROM (
    SELECT 
        CASE WHEN CURDATE() BETWEEN StartDate AND EndDate 
             THEN LowerPrice ELSE HigherPrice END AS applied_price
    FROM ConditionalSelect
) AS t;

Các biến thể hữu ích

1. Tham số hóa ngày (không dùng CURDATE)

SET @check_date = '2019-04-05';
SELECT MIN(CASE WHEN @check_date BETWEEN StartDate AND EndDate THEN LowerPrice ELSE HigherPrice END)
FROM ConditionalSelect;

2. Nhiều mức giá (Tiered pricing)

SELECT 
    MIN(CASE 
        WHEN CURDATE() BETWEEN StartDate AND EndDate THEN Price1
        WHEN CURDATE() BETWEEN StartDate2 AND EndDate2 THEN Price2
        ELSE BasePrice END) AS MinPrice
FROM pricing_table;

3. Áp dụng cho từng sản phẩm (GROUP BY)

SELECT ProductId,
    MIN(CASE WHEN CURDATE() BETWEEN StartDate AND EndDate THEN SalePrice ELSE RegularPrice END) AS CurrentMinPrice
FROM product_pricing
GROUP BY ProductId;

Lưu ý hiệu năng

  • BETWEEN trên cột DATE/DATETIME có thể dùng index
  • Tránh hàm trên cột: DATE(StartDate) <= CURDATE() → không dùng index
  • Viết: StartDate <= @check_date AND EndDate >= @check_date cho index range scan