SQLITE: Sự cố về thẻ và sản phẩm


10

Tôi đang tìm cách tạo một truy vấn để thực hiện các thao tác sau:

Hãy xem xét 3 bảng:

  • sản phẩm: Danh mục sản phẩm
  • tags: danh sách các thẻ
  • tag_IES: bảng được sử dụng để liên kết thẻ với sản phẩm

Hãy xem xét cấu trúc này cho mỗi bảng:

Các sản phẩm:

  • id (int, tự động tăng)
  • tên (varchar, tên của sản phẩm)

Tags:

  • id (int autorement)
  • nhãn (varchar, nhãn của thẻ)

Tag_ies:

  • id (int, tự động tăng)
  • tag_id (int, tham chiếu đến id thẻ)
  • ref_id (int, tham chiếu đến id sản phẩm)

Những gì tôi muốn:

Lấy tất cả các sản phẩm được gắn thẻ id 10, 11 và 12 chẳng hạn.

Truy vấn này không hoạt động, vì nó trả về các sản phẩm có ít nhất một trong các thẻ:

select 
    p.name as name,
    p.id as id
from 
    products p inner join tag_ties ties
on
    p.id=ties.ref_id
where
    ties.ref_id=p.id and
    ties.tag_id in (10,11,12)
group by 
    p.id
order by 
    p.name asc

Câu trả lời:


9

Hãy thử một cái gì đó như thế này:

select
    t1.id,
    t1.name
from
    (
    select
        p.name as name,
        p.id as id
    from
        products p inner join tag_ties ties
    on
        p.id=ties.ref_id
    where
        ties.tag_id in (10,11,12)
    ) as t1
group by
    t1.id,
    t1.name
having
    count(t1.id) = 3
order by
    t1.name asc
;

Nó hoạt động :)
Julien L

11

Bạn có thể giải quyết vấn đề này bằng cách sử dụng các câu lệnh giao nhau. Thực hiện một lựa chọn riêng cho mỗi tag_id và nối chúng với các giao điểm và bạn sẽ chỉ nhận được các bản ghi khớp với cả ba tag_ids.

select products.id, products.name from 
products join tag_ties
on tag_ties.ref_id = products.id
where tag_ties.tag_id = 10
intersect
select products.id, products.name from 
products join tag_ties
on tag_ties.ref_id = products.id 
where tag_ties.tag_id = 11
intersect
select products.id, products.name from 
products join tag_ties
on tag_ties.ref_id = products.id 
where tag_ties.tag_id = 12

Đây là một bài viết tham khảo về việc sử dụng giao cắt

Bạn cũng có thể sử dụng chế độ xem tạm thời để làm cho giao diện này đẹp hơn một chút.

create temporary view temp_view as 
select name, products.id as id, tag_ties.tag_id as tag_id 
from products join tag_ties
on tag_ties.ref_id = products.id

select name, id from temp_view where tag_id = 10
intersect ...

8

Truy vấn con từ câu trả lời được chọn là không cần thiết. Để chọn sản phẩm có tất cả id thẻ đã cho, truy vấn có thể chỉ đơn giản là:

SELECT 
    p.*
FROM 
    products AS p
INNER JOIN
    tag_ties AS tt
ON
    tt.ref_id = p.id
AND 
    tt.tag_id IN (10, 11, 12)
GROUP BY 
    p.id
HAVING 
    COUNT(p.id)=3

Mở rộng ý tưởng này, chúng tôi cũng có thể truy vấn dựa trên nhãn thẻ trong một lần chụp. Để chọn sản phẩm có thẻ ('foo', 'bar', 'baz'):

SELECT 
    p.*
FROM 
    products AS p
INNER JOIN
    tags AS t
ON
    t.label IN ('foo', 'bar', 'baz')
INNER JOIN
    tag_ties AS tt
ON
    tt.ref_id = p.id
AND 
    tt.tag_id = t.id
GROUP BY 
    p.id
HAVING 
    COUNT(p.id)=3

Để làm phức tạp nó một chút, chúng ta có thể sử dụng truy vấn con để trộn giao điểm ( AND) và union ( OR). Truy vấn bên dưới sẽ trả về các sản phẩm có tất cả các thẻ của nhóm ('foo', 'bar')và ít nhất một trong các thẻ của nhóm ('baz', 'ding'):

SELECT 
    p.*
FROM 
    (
    SELECT 
        p.*
    FROM 
        products AS p
    INNER JOIN 
        tags AS t
    ON
        t.label IN ('foo', 'bar')
    INNER JOIN 
        tag_ties AS tt
    ON
        tt.ref_id = p.id
    AND 
        tt.tag_id = t.id
    GROUP BY 
        p.id
    HAVING 
        COUNT(p.id)=2
    ) AS p
INNER JOIN 
    tags AS t
ON 
    t.label IN ('baz', 'ding')
INNER JOIN
    tag_ties AS tt
ON
    tt.ref_id = p.id
AND 
    tt.tag_id = t.id
GROUP BY 
    p.id

2
Bạn không cần một JOIN? Không, về mặt kỹ thuật bạn không nhưng có lý do nào để không sử dụng nó không? Và quay trở lại ký hiệu SQL-89 của các phép nối ngầm?
ypercubeᵀᴹ

5
Tôi đang từ chối vì bạn nên sử dụng THAM GIA luôn. stackoverflow.com/questions/5654278/ nếu không có THAM GIA rõ ràng, mã của bạn sẽ không được triển khai trong cửa hàng của tôi
gbn

3
Này các bạn, cảm ơn vì đã nói với tôi rằng tham gia ngầm là phong cách xấu. Tôi chủ yếu dự định chỉ ra rằng truy vấn con từ câu trả lời được chọn là không cần thiết. Tôi chỉnh sửa câu trả lời để sử dụng tham gia. Nếu bạn thấy bất cứ điều gì sai trong các truy vấn của tôi xin vui lòng cho tôi biết.
moraes

5
+1 để nhận downvote mà không khó chịu và thực sự cân nhắc lời khuyên để cải thiện kỹ năng của bạn.
Zane

2
Những gì @Zane nói. +1 cũng vậy
gbn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.