SQLITE : 태그 및 제품 문제


10

다음을 수행하기 위해 쿼리를 만드는 방법을 찾고 있습니다.

3 개의 테이블을 고려해 봅시다 :

  • 제품 : 제품 목록
  • 태그 : 태그 목록
  • tag_ties : 태그를 제품에 연결하는 데 사용되는 테이블

각 테이블에 대해이 구조를 고려하십시오.

제품:

  • id (int, 자동 증가)
  • 이름 (varchar, 제품 이름)

태그 :

  • id (int 자동 증가)
  • 라벨 (varchar, 태그 라벨)

Tag_ties :

  • id (int, 자동 증가)
  • tag_id (int, 태그 ID 참조)
  • ref_id (int, 제품 ID 참조)

내가 원하는 것 :

예를 들어 태그 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_id와 일치하는 레코드 만 얻을 수 있습니다.

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

선택한 답변의 하위 쿼리가 필요하지 않습니다. 주어진 모든 태그 ID를 가진 제품을 선택하기 위해 쿼리는 다음과 같습니다.

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
항상 JOIN 을 사용해야 하므로 다운 보팅 중 입니다. stackoverflow.com/questions/5654278/… 명시적인 JOIN이 없으면 코드가 내 가게에 배포되지 않습니다
gbn

3
얘들 아, 암시적인 조인은 나쁜 스타일이라고 말해 주셔서 감사합니다. 나는 주로 선택된 답변의 하위 쿼리가 필요하지 않다는 것을 지적하려고했습니다. 조인을 사용하도록 답변을 편집했습니다. 내 질문에 다른 문제가 있으면 알려주십시오.
moraes

5
화를 내지 않고 실제로 기술을 향상시키기 위해 조언을 고려하여 공감대를 가져 가면 +1입니다.
Zane

2
@Zane이 말한 것. +1도
gbn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.