2009-10-27 66 views
5

Giản Bảng cấu trúc:Mysql GROUP BY và COUNT cho nhiều mệnh đề WHERE

CREATE TABLE IF NOT EXISTS `hpa` (
    `id` bigint(15) NOT NULL auto_increment, 
    `core` varchar(50) NOT NULL, 
    `hostname` varchar(50) NOT NULL, 
    `status` varchar(255) NOT NULL, 
    `entered_date` int(11) NOT NULL, 
    `active_date` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `hostname` (`hostname`), 
    KEY `status` (`status`), 
    KEY `entered_date` (`entered_date`), 
    KEY `core` (`core`), 
    KEY `active_date` (`active_date`) 
) 

Đối với điều này, tôi có các truy vấn SQL sau đây mà chỉ đơn giản ước giá trị lên toàn bộ hồ sơ với tình trạng xác định.

SELECT core,COUNT(hostname) AS hostname_count, MAX(active_date) AS last_active 
      FROM `hpa` 
      WHERE 
      status != 'OK' AND status != 'Repaired' 
      GROUP BY core 
      ORDER BY core 

Truy vấn này đã được đơn giản hóa để loại bỏ INNER JOINS thành dữ liệu không liên quan và các cột phụ không ảnh hưởng đến câu hỏi.

MAX (active_date) là giống nhau cho tất cả các bản ghi của một ngày cụ thể và phải luôn chọn ngày gần đây nhất hoặc cho phép chênh lệch từ NOW(). (Đó là một lĩnh vực UNIXTIME)

Tôi muốn cả hai tội danh: (! Status = 'OK' tình trạng VÀ = 'sửa chữa')

VÀ nghịch đảo ... đếm: (status = 'OK 'OR status = 'sửa chữa')

VÀ câu trả lời đầu tiên chia thứ hai, cho 'percentage_dead'(có lẽ cũng nhanh để làm trong bài chế biến)

cHO ngày gần đây nhất hoặc một bù đắp (- 86400 cho ngày hôm qua, v.v ..)

Bảng chứa khoảng 500 nghìn bản ghi và phát triển bởi khoảng 5000 một ngày để một truy vấn SQL đơn như trái ngược với vòng lặp sẽ thực sự tốt đẹp ..

Tôi tưởng tượng một số IF sáng tạo có thể làm điều này. Bạn chuyên môn được đánh giá cao.

EDIT: Tôi đang mở để sử dụng truy vấn SQL khác cho dữ liệu ngày hôm nay hoặc dữ liệu từ bù trừ.

CHỈNH SỬA: Tác vụ truy vấn, đủ nhanh, nhưng hiện tại tôi không thể để người dùng sắp xếp theo cột phần trăm (cột có nguồn gốc từ số lượng xấu và số lượng tốt). Đây không phải là một stopper hiển thị, nhưng tôi cho phép họ để sắp xếp trên tất cả mọi thứ khác. Các ORDER BY về điều này:

SELECT h1.core, MAX(h1.entered_date) AS last_active, 
SUM(CASE WHEN h1.status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS good_host_count, 
SUM(CASE WHEN h1.status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS bad_host_count 
FROM `hpa` h1 
LEFT OUTER JOIN `hpa` h2 ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date) 
WHERE h2.hostname IS NULL 
GROUP BY h1.core 
ORDER BY (bad_host_count/(bad_host_count + good_host_count)) DESC,h1.core 

Cung cấp cho tôi: # 1247 - Tham khảo 'bad_host_count' không được hỗ trợ (tham chiếu đến chức năng nhóm)

EDIT: Solved cho một bộ phận khác nhau. Các công trình và cho phép tôi để ORDER BY percentage_dead

SELECT c.core, c.last_active, 
SUM(CASE WHEN d.dead = 1 THEN 0 ELSE 1 END) AS good_host_count, 
SUM(CASE WHEN d.dead = 1 THEN 1 ELSE 0 END) AS bad_host_count, 
(SUM(CASE WHEN d.dead = 1 THEN 1 ELSE 0 END) * 100/ 
((SUM(CASE WHEN d.dead = 1 THEN 0 ELSE 1 END))+(SUM(CASE WHEN d.dead = 1 THEN 1 ELSE 0 END)))) AS percentage_dead 
FROM `agent_cores` c 
LEFT JOIN `dead_agents` d ON c.core = d.core 
WHERE d.active = 1 
GROUP BY c.core 
ORDER BY percentage_dead 

Trả lời

3

Nếu tôi hiểu sau đây, bạn muốn có được một số lượng về tình trạng của OK vs hostname không OK, kể từ ngày hoạt động cuối cùng. Đúng? Và sau đó nên được nhóm lại theo cốt lõi.

SELECT core, MAX(active_date) 
    SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS OK_host_count, 
    SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS broken_host_count 
FROM `hpa` h1 LEFT OUTER JOIN `hpa` h2 
    ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date) 
WHERE h2.hostname IS NULL 
GROUP BY core 
ORDER BY core; 

Đây là biến thể của vấn đề "lớn nhất trên mỗi nhóm" mà tôi thấy rất nhiều trong câu hỏi SQL trên StackOverflow.

Trước tiên, chỉ muốn chọn các hàng có ngày hoạt động mới nhất trên mỗi tên máy chủ, chúng tôi có thể thực hiện bằng cách thực hiện kết nối bên ngoài cho các hàng có cùng tên máy chủ và một active_date lớn hơn. Nơi chúng tôi không tìm thấy kết quả phù hợp như vậy, chúng tôi đã có các hàng mới nhất cho mỗi tên máy chủ đã cho.

Sau đó nhóm theo lõi và đếm các hàng theo trạng thái.

Đó là giải pháp cho ngày hôm nay (giả sử không có hàng nào có active_date trong tương lai).Để hạn chế kết quả thành các hàng N ngày trước, bạn phải hạn chế cả hai bảng.

SELECT core, MAX(active_date) 
    SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS OK_host_count, 
    SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS broken_host_count 
FROM `hpa` h1 LEFT OUTER JOIN `hpa` h2 
    ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date 
    AND h2.active_date <= CURDATE() - INTERVAL 1 DAY) 
WHERE h1.active_date <= CURDATE() - INTERVAL 1 DAY AND h2.hostname IS NULL 
GROUP BY core 
ORDER BY core; 

Về tỷ lệ giữa tên máy chủ lưu trữ bị hỏng và tên máy chủ bị hỏng, tôi khuyên bạn nên tính toán trong mã PHP của mình. SQL không cho phép bạn tham chiếu các bí danh cột trong các biểu thức chọn danh sách khác, vì vậy bạn phải bao bọc phần trên như một truy vấn con và điều đó phức tạp hơn giá trị của nó trong trường hợp này.


Tôi quên bạn đã nói bạn đang sử dụng dấu thời gian UNIX. Làm điều gì đó như sau:

SELECT core, MAX(active_date) 
    SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 1 ELSE 0 END) AS OK_host_count, 
    SUM(CASE WHEN status IN ('OK', 'Repaired') THEN 0 ELSE 1 END) AS broken_host_count 
FROM `hpa` h1 LEFT OUTER JOIN `hpa` h2 
    ON (h1.hostname = h2.hostname AND h1.active_date < h2.active_date 
    AND h2.active_date <= UNIX_TIMESTAMP() - 86400) 
WHERE h1.active_date <= UNIX_TIMESTAMP() - 86400 AND h2.hostname IS NULL 
GROUP BY core 
ORDER BY core; 
+0

Cảm ơn bạn Bill! Không thể kiểm tra điều này ngay lập tức mặc dù tôi đã làm trong ngày. Phần đầu tiên tôi nhận được. Tôi sẽ phải nghiên cứu thứ hai trong một thời gian tôi nghĩ. :) –

+0

Nó thực sự là một thời gian lưu trữ int, không phải DATETIME. Tạo nên sự khác biệt? –

+0

Ok, nó thay đổi cách bạn tính toán bù trừ, nhưng không phải là logic chung. Tôi sẽ thêm một ví dụ. –