2011-09-12 37 views
5

Tôi có một vấn đề vượt xa tôi (tôi thực sự rất vui mừng Tôi là bản Beta) liên quan đến các bản sao (vì vậy GROUP BY, HAVING, COUNT), được kết hợp bằng cách giữ giải pháp trong các hàm chuẩn đi kèm với SQLite. Tôi đang sử dụng mô-đun sqlite3 từ Python.CHỌN "đầu tiên" (được xác định bởi ORDER BY) hàng TỪ các hàng gần trùng lặp (được xác định bởi GROUP BY, HAVING, COUNT) trong SQLite

nhân bảng Ví dụ, Cột:

* ID: integer, auto-incrementing 
* ColA: integer 
* ColB: varchar(20) 
* UserType: varchar(20) 
* LoadMe: Boolean 

(Vâng, kiểu dữ liệu SQLite của là không đáng kể)

bảng dữ liệu của tôi, người lao động, khi khởi động trông giống như:

ID ColA ColB UserType LoadMe 
1 1  a  Alpha  0 
2 1  b  Beta  0 
3 2  a  Alpha  0 
4 2  a  Beta  0 
5 2  b  Delta  0 
6 2  b  Alpha  0 
7 1  a  Delta  0 
8 1  b  Epsilon 0 
9 1  c  Gamma  0 
10 4  b  Delta  0 
11 5  a  Alpha  0 
12 5  a  Beta  0 
13 5  b  Gamma  0 
14 5  a  Alpha  0 

Tôi muốn để kích hoạt, để tải lên xe tải tại một nhà máy mới, tất cả các công nhân có sự kết hợp độc đáo giữa ColA và ColB. Đối với những người trùng lặp (cặp song sinh, ba, vv, có lẽ thông qua quá trình Bokanovsky), nơi kết hợp độc đáo của ColA và ColB có nhiều hơn một công nhân, tôi muốn chọn chỉ một từ mỗi tập hợp các bản sao. Để làm cho vấn đề khó khăn hơn, tôi muốn bổ sung có thể tạo một lựa chọn từ mỗi bộ bản sao trên cơ sở UserType dưới một số hình thức ORDER BY. Tôi có thể muốn chọn "trùng lặp" đầu tiên với Loại người dùng là "Alpha" để làm việc trên một vấn đề thông minh khủng khiếp hoặc ORDER BY UserType DESC, rằng tôi có thể ra lệnh cho bộ áo chẽn màu đen cho người lao động thấp nhất.

Bạn có thể thấy rằng các ID 9, 10 và 13 có các kết hợp độc đáo của ColA và ColB và dễ xác định nhất. Tuy nhiên, các kết hợp 1-a, 1-b, 2-a, 2-b và 5-a có các bản sao bên trong chúng.

Quy trình hiện tại của tôi, như hiện tại:

0) Mọi người đều có số ID duy nhất. Điều này được thực hiện khi sinh.

1) SET tất cả người lao động để LoadMe = 1.

UPDATE Workers 
SET LoadMe = 1 

2) Tìm bản sao của tôi dựa trên sự tương đồng của họ trong hai cột (GROUP BY Cola, ColB):

SELECT Wk1.* 
FROM Workers AS Wk1 
INNER JOIN (
    SELECT ColA, ColB 
    FROM Workers 
    GROUP BY ColA, ColB 
    HAVING COUNT(*) > 1 
) AS Wk2 
ON Wk1.ColA = Wk2.ColA 
AND Wk1.ColB = Wk2.ColB 
ORDER BY ColA, ColB 

3) Đặt tất cả các bản sao của tôi thành LoadMe = 0.

UPDATE Workers 
SET LoadMe = 0 
WHERE ID IN (
    SELECT Wk1.ID 
    FROM Workers AS Wk1 
    INNER JOIN (
     SELECT ColA, ColB 
     FROM Workers 
     GROUP BY ColA, ColB 
     HAVING COUNT(*) > 1 
    ) AS Wk2 
    ON Wk1.ColA = Wk2.ColA 
    AND Wk1.ColB = Wk2.ColB 
) 

4) Đối với mỗi bộ bản sao trong sốcủa tôi, ORDER ed BY UserType, SELECT chỉ có một, là người đầu tiên trong danh sách, để có LoadMe SET để 1.

Bảng này sẽ như thế nào:

ID ColA ColB UserType LoadMe 
1 1  a  Alpha  1 
2 1  b  Beta  1 
3 2  a  Alpha  1 
4 2  a  Beta  0 
5 2  b  Delta  0 
6 2  b  Alpha  1 
7 1  a  Delta  0 
8 1  b  Epsilon 0 
9 1  c  Gamma  1 
10 4  b  Delta  1 
11 5  a  Alpha  1 
12 5  a  Beta  0 
13 5  b  Gamma  1 
14 5  a  Alpha  0 

ORDER ed BY Cola, ColB, loại người dùng, sau đó ID và được chia nhỏ theo các cột GROUP BY, (và cuối cùng là khoảng cách rõ ràng) mà cùng một dữ liệu có thể trông giống như:

ID ColA ColB UserType LoadMe 
1 1  a  Alpha  1 
7 1  a  Delta  0 

2 1  b  Beta  1 
8 1  b  Epsilon 0 

9 1  c  Gamma  1 

3 2  a  Alpha  1 
4 2  a  Beta  0 

6 2  b  Alpha  1 
5 2  b  Delta  0 

10 4  b  Delta  1 

11 5  a  Alpha  1 
14 5  a  Alpha  0 
12 5  a  Beta  0 

13 5  b  Gamma  1 

Tôi là bối rối ở bước cuối cùng và cảm thấy như một nửa bán Epsilon-minus.Trước đây tôi đã kéo các bản sao ra khỏi cơ sở dữ liệu vào không gian chương trình và làm việc trong Python, nhưng tình huống này phát sinh không thường xuyên và tôi muốn giải quyết vĩnh viễn hơn điều này.

Trả lời

1

Tôi muốn giải quyết vấn đề như thế này một chút. Bước đầu tiên là xác định cặp ColA, ColB duy nhất:

SELECT ColA,ColB FROM Workers GROUP BY ColA,ColB 

Bây giờ cho mỗi cặp bạn muốn tìm hồ sơ ưu tiên cao nhất. Một tham gia sẽ không làm việc bởi vì bạn sẽ kết thúc với nhiều bản ghi cho mỗi cặp độc đáo nhưng một subquery sẽ làm việc:

SELECT ColA,ColB, 
    (SELECT id FROM Workers w1 
    WHERE w1.ColA=w2.ColA AND w1.ColB=w2.ColB 
    ORDER BY UserType LIMIT 1) AS id 
FROM Workers w2 GROUP BY ColA,ColB; 

Bạn có thể thay đổi các điều khoản ORDER BY trong subquery để kiểm soát ưu tiên. LIMIT 1 đảm bảo rằng chỉ có một bản ghi cho mỗi truy vấn con (nếu không sqlite sẽ trả lại bản ghi cuối cùng khớp với mệnh đề WHERE, mặc dù tôi không chắc chắn rằng điều đó được đảm bảo).

Kết quả của truy vấn này là danh sách các bản ghi được tải với ColA, ColB, id. Tôi có lẽ sẽ làm việc trực tiếp từ đó và thoát khỏi LoadMe nhưng nếu bạn muốn giữ lại nó, bạn có thể làm điều này:

BEGIN TRANSACTION; 
UPDATE Workers SET LoadMe=0; 
UPDATE Workers SET LoadMe=1 
WHERE id IN (SELECT 
    (SELECT id FROM Workers w1 
    WHERE w1.ColA=w2.ColA AND w1.ColB=w2.ColB 
    ORDER BY UserType LIMIT 1) AS id 
    FROM Workers w2 GROUP BY ColA,ColB); 
COMMIT; 

Đó xóa cờ LoadMe và sau đó đặt nó vào 1 cho mỗi người trong số các hồ sơ được trả về bởi chúng tôi truy vấn cuối cùng. Giao dịch đảm bảo rằng tất cả điều này diễn ra hoặc không thành một bước và không bao giờ rời khỏi các trường LoadMe của bạn ở trạng thái không nhất quán.

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