Tôi đã có một tập hợp các thành phố có mối quan hệ nhiều - nhiều với một bộ thẻ. Người dùng cung cấp cho tôi một bộ sưu tập các thẻ (có thể chứa các bản sao!) và tôi cần phải trả về một danh sách các mục phù hợp, được sắp xếp theo mức độ liên quan.Truy vấn SQL để tìm kiếm theo nhiều thẻ có phân loại phù hợp
Data
Dưới đây là một số dữ liệu mẫu để minh họa cho vấn đề:
Cities:
--------------------
| id | city |
--------------------
| 1 | Atlanta |
| 2 | Baltimore |
| 3 | Cleveland |
| 4 | Denver |
| 5 | Eugene |
--------------------
Tags:
------
| id |
------
| 1 |
| 2 |
| 3 |
| 4 |
------
Các thành phố được gắn thẻ như thế này:
Atlanta: 1, 2
Baltimore: 3
Cleveland: 1, 3, 4
Denver: 2, 3
Eugene: 1, 4
... vì vậy các bảng CityTags trông giống như:
------------------------
| city_id | tag_id |
------------------------
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
| 3 | 1 |
| 3 | 3 |
| 3 | 4 |
| 4 | 2 |
| 4 | 3 |
| 5 | 1 |
| 5 | 4 |
------------------------
Ví dụ 1
Nếu người dùng mang lại cho tôi id tag: [1, 3, 3, 4], tôi muốn đếm có bao nhiêu trận đấu tôi đã cho mỗi người trong số các thẻ, và trả về một kết quả phù hợp-được sắp xếp như sau:
------------------------
| city | matches |
------------------------
| Cleveland | 4 |
| Baltimore | 2 |
| Eugene | 2 |
| Atlanta | 1 |
| Denver | 1 |
------------------------
Kể từ Cleveland phù hợp tất cả bốn thẻ, nó đầu tiên, tiếp theo là Baltimore và Eugene, mà mỗi người có hai thẻ trận đấu, v.v.
Ví dụ 2
Một ví dụ khác để thực hiện biện pháp tốt. Đối với việc tìm kiếm [2, 2, 2, 3, 4], chúng tôi nhận được:
------------------------
| city | matches |
------------------------
| Denver | 4 |
| Atlanta | 3 |
| Cleveland | 2 |
| Baltimore | 1 |
| Eugene | 1 |
------------------------
SQL
Nếu tôi bỏ qua các thẻ lặp đi lặp lại, thì đó là tầm thường:
SELECT name,COUNT(name) AS relevance FROM
(SELECT name FROM cities,citytags
WHERE id=city_id AND tag_id IN (1,3,3,4)) AS matches
GROUP BY name ORDER BY relevance DESC;
Nhưng đó không phải là những gì tôi cần. Tôi cần phải tôn trọng các bản sao. Ai đó có thể đề nghị làm thế nào tôi có thể thực hiện điều này?
Giải pháp trong Postgresql
Aha! Một bảng tạm thời là tôi cần. Postgresql cho phép tôi làm điều này với cú pháp WITH của nó. Đây là giải pháp:
WITH search(tag) AS (VALUES (1), (3), (3), (4))
SELECT name, COUNT(name) AS relevance FROM cities
INNER JOIN citytags ON cities.id=citytags.city_id
INNER JOIN search ON citytags.tag_id=search.tag
GROUP BY name ORDER BY relevance DESC;
Cảm ơn rất nhiều đến những người đã trả lời.
Người dùng nhập danh sách thẻ của họ như thế nào? Họ có nhập danh sách được phân cách bằng dấu phẩy mà sau đó bạn chỉ cần ghép nối vào truy vấn không? – mellamokb