SQLITE: ปัญหาของแท็กและผลิตภัณฑ์


10

ฉันกำลังค้นหาวิธีในการสร้างแบบสอบถามเพื่อทำสิ่งต่อไปนี้:

ลองพิจารณา 3 ตาราง:

  • ผลิตภัณฑ์: รายชื่อผลิตภัณฑ์
  • แท็ก: รายการของแท็ก
  • tag_ties: ตารางที่ใช้เชื่อมโยงแท็กกับผลิตภัณฑ์

ลองพิจารณาโครงสร้างนี้สำหรับแต่ละตาราง:

ผลิตภัณฑ์:

  • id (int, autoincrement)
  • ชื่อ (varchar ชื่อของผลิตภัณฑ์)

Tags:

  • id (การสร้างอัตโนมัติภายใน)
  • ป้ายกำกับ (varchar ป้ายกำกับของแท็ก)

Tag_ties:

  • id (int, autoincrement)
  • tag_id (int หมายถึง id แท็ก)
  • ref_id (int หมายถึงรหัสผลิตภัณฑ์)

สิ่งที่ฉันต้องการ:

รับผลิตภัณฑ์ทั้งหมดที่ติดแท็กด้วยแท็ก id 10, 11 และ 12 เช่น

แบบสอบถามนี้ไม่ทำงานเนื่องจากจะส่งคืนผลิตภัณฑ์ที่มีแท็กอย่างน้อยหนึ่งรายการ:

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

คำตอบ:


9

ลองสิ่งนี้:

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
;

มันใช้งานได้แล้ว :)
Julien L

11

คุณสามารถแก้ปัญหานี้โดยใช้คำสั่งตัดกัน ทำการเลือกแยกต่างหากสำหรับแต่ละ tag_id และเข้าร่วมกับจุดตัดและคุณจะได้รับระเบียนที่ตรงกับ 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

นี่คือบทความอ้างอิงเกี่ยวกับการใช้จุดตัด

คุณยังสามารถใช้มุมมองชั่วคราวเพื่อทำให้ลักษณะนี้ดูดีขึ้นเล็กน้อย

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

ไม่จำเป็นต้องใช้แบบสอบถามย่อยจากคำตอบที่เลือก ในการเลือกผลิตภัณฑ์ที่มีรหัสแท็กที่ระบุทั้งหมดสามารถทำได้ง่ายๆ:

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

การขยายแนวคิดนี้เราสามารถค้นหาตามป้ายกำกับของแท็กในช็อตเดียว ในการเลือกผลิตภัณฑ์ที่มีแท็ก('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

หากต้องการทำให้ซับซ้อนขึ้นเล็กน้อยเราสามารถใช้แบบสอบถามย่อยเพื่อผสมทางแยก ( AND) และสหภาพ ( OR) แบบสอบถามด้านล่างจะส่งคืนผลิตภัณฑ์พร้อมแท็กทั้งหมดของกลุ่ม('foo', 'bar')และอย่างน้อยหนึ่งแท็กของกลุ่ม('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
คุณไม่จำเป็นต้องมีJOIN? ไม่คุณไม่ได้ใช้เทคนิค แต่มีเหตุผลที่จะไม่ใช้หรือไม่ และจะกลับไปที่การรวม SQL-89 ของการรวมโดยนัย?
ypercubeᵀᴹ

5
ฉันกำลังลงเนื่องจากคุณควรใช้เข้าร่วมเสมอ stackoverflow.com/questions/5654278/…หากไม่ได้เข้าร่วมอย่างชัดเจนรหัสของคุณจะไม่ถูกนำไปใช้ในร้านค้าของฉัน
gbn

3
เฮ้พวกขอบคุณที่บอกฉันว่าการเข้าร่วมโดยปริยายเป็นสไตล์ที่ไม่ดี ฉันตั้งใจจะชี้ให้เห็นว่าแบบสอบถามย่อยจากคำตอบที่เลือกนั้นไม่จำเป็น ฉันแก้ไขคำตอบเพื่อใช้การเข้าร่วม หากคุณเห็นสิ่งอื่นใดผิดในการค้นหาของฉันโปรดแจ้งให้เราทราบ
moraes

5
+1 สำหรับการลงคะแนนโดยไม่รู้สึกหงุดหงิดและนำคำแนะนำมาพิจารณาเพื่อพัฒนาทักษะของคุณ
เชน

2
@Zane พูดอะไร +1 ด้วย
gbn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.