2012-08-01 34 views
5

Tôi muốn tính số lần mỗi người dùng có hàng trong '5' của nhau.SQL: tìm sự khác biệt giữa các hàng

Ví dụ: Don - 501 và Don - 504 nên được tính, trong khi Don - 501 và Don - 1600 không được tính.

bắt đầu:

Name  value 
_________ ______________ 
Don   1235 
Don   6012 
Don   6014 
Don   6300 
James  9000 
James  9502 
James  9600 
Sarah  1110 
Sarah  1111 
Sarah  1112 
Sarah  1500 
Becca  0500 
Becca  0508 
Becca  0709 

Kết thúc:

Name   difference_5 
__________  _____________ 
Don    1 
James   0 
Sarah   2 
Becca   0 
+3

có thể là đôi mắt của tôi nhưng dữ liệu của bạn dường như không khớp với mô tả văn bản .... _Don - 501 và Don - 504 phải được tính_ nhưng tôi không thấy các giá trị này. – Taryn

+0

Bạn có thể giải thích tại sao số lượng của Sarah không phải là 3? 1110 đến 1111 là 1, 1111 đến 1112 là 2, 1110 đến 1112 là 3, phải không? Hay đó không phải là cách bạn đang làm nó? – mikeY

Trả lời

2

Sử dụng ABS() chức năng, kết hợp với một tự tham gia vào một subquery:

Vì vậy, một cái gì đó như:

SELECT name, COUNT(*)/2 AS difference_5 
FROM (
    SELECT a.name name, ABS(a.value - b.value) 
    FROM tbl a JOIN tbl b USING(name) 
    WHERE ABS(a.value - b.value) BETWEEN 1 AND 5 
) AS t GROUP BY name 

được chỉnh sửa theo nhận xét của Andreas.

+0

Tôi nghĩ rằng điều này sẽ bao gồm tất cả hoán vị của a và b, có nghĩa là, cho "Don 6012" và "Don 6014" sẽ có hai hàng với sự khác biệt 2. Đây sẽ phải được lọc ra bằng cách nào đó; có thể chia làm hai? – Andreas

+0

Điểm tốt. Đã chỉnh sửa, cảm ơn! –

+0

MySQL không thích 'khác biệt' trong mệnh đề WHERE. (MySQL 5.5) –

0

Vì OP cũng muốn không đếm, chúng tôi sẽ cần tham gia tự tiếp tục. Logic bổ sung là cần thiết nếu một người có hai giá trị chính xác giống nhau, chúng cũng chỉ được tính một lần.

WITH cnts AS (
     WITH pair AS (
       SELECT t1.zname,t1.zvalue 
       FROM ztable t1 
       JOIN ztable t2 
       ON t1.zname = t2.zname 
       WHERE (t1.zvalue < t2.zvalue 
         AND t1.zvalue >= t2.zvalue - 5) 
       OR (t1.zvalue = t2.zvalue AND t1.ctid < t2.ctid) 
       ) 
     SELECT DISTINCT zname 
     , COUNT(*) AS znumber 
     FROM pair 
     GROUP BY zname 
     ) 
, names AS (
     SELECT distinct zname AS zname 
     FROM ztable 
     GROUP BY zname 
     ) 
SELECT n.zname 
     , COALESCE(c.znumber,0) AS znumber 
FROM names n 
LEFT JOIN cnts c ON n.zname = c.zname 
     ; 

KẾT QUẢ:

DROP SCHEMA 
CREATE SCHEMA 
SET 
CREATE TABLE 
INSERT 0 14 
zname | znumber 
-------+--------- 
Sarah |  3 
Don |  1 
Becca |  0 
James |  0 
(4 rows) 

LƯU Ý: xin lỗi vì sự CTE, tôi đã không nhìn thấy thẻ mysql thứ, tôi chỉ thích vấn đề ;-)

+2

MySql có hỗ trợ CTE không? Tôi không nghĩ rằng nó có chức năng đó. – Taryn

+0

Tôi chỉ nhận thấy rằng bản thân mình. Tôi vẫn thích các giải pháp, mặc dù ... (và vấn đề là nhiều hơn hoặc ít chung) – wildplasser

+0

Sẽ dễ dàng hơn với chức năng cửa sổ ('lag()' nói đến cái tâm) –

0
SELECT 
    A.Name, 
    SUM(CASE WHEN (A.Value < B.Value) AND (A.Value >= B.Value - 5) THEN 1 ELSE 0 END) Difference_5 
FROM 
    tbl A INNER JOIN 
    tbl B USING(Name) 
GROUP BY 
    A.Name 
1

Giả sử rằng mỗi name ->value cặp là duy nhất, điều này sẽ giúp bạn đếm số lần giá trị nằm trong phạm vi 5 cho mỗi tên:

SELECT a.name, 
      COUNT(b.name)/2 AS difference_5 
FROM  tbl a 
LEFT JOIN tbl b ON a.name = b.name AND 
        a.value <> b.value AND 
        ABS(a.value - b.value) <= 5 
GROUP BY a.name 

Như bạn sẽ thấy, chúng tôi cũng phải loại trừ các cặp bằng với chính chúng.

Nhưng nếu bạn muốn đếm số lần giá trị của mỗi tên đến trong vòng 5 của bất kỳ giá trị trong bảng, bạn có thể sử dụng:

SELECT a.name, 
      COUNT(b.name)/2 AS difference_5 
FROM  tbl a 
LEFT JOIN tbl b ON NOT (a.name = b.name AND a.value = b.value) AND 
        ABS(a.value - b.value) <= 5 
GROUP BY a.name 

Xem SQLFiddle Demo cho cả các giải pháp.

Các vấn đề liên quan