복붙노트

[SQL] 조인에서 여러 행에 조건을 적용하기위한 SQL

SQL

조인에서 여러 행에 조건을 적용하기위한 SQL

나는 내 질문에 대한 답을 찾은 것 같아, 나는 내가 SQL 오류가 계속 구문의 단지 확실 해요.

기본적으로, IN의 반대를하고 싶어. 이 예제를 보자

SELECT * 
  FROM users INNER JOIN 
       tags ON tags.user_id = users.id 
 WHERE tags.name IN ('tag1', 'tag2');

위는 'tag1로'OR '이 tag2'을 가지고있는 사용자를 반환합니다. 둘 다있는 사용자를 원한다. 그들은 모두 태그를 반환 할 수 있어야합니다. 나는 키워드 ALL 사용해야 겠지,하지만 일에 그것을 얻을 수 없습니다.

당신의 도움을 주셔서 감사합니다.

해결법

  1. ==============================

    1.다시 태그 테이블에 가입 할 수 있습니다.

    다시 태그 테이블에 가입 할 수 있습니다.

    SELECT * FROM users
    INNER JOIN tags as t1 on t1.user_id = users.id and t1.name='tag1'
    INNER JOIN tags as t2 on t2.user_id = users.id and t2.name='tag2'
    
  2. ==============================

    2.먼저 일반적으로이 문제에 대한하자의 이야기, 다음 세부 사항.

    먼저 일반적으로이 문제에 대한하자의 이야기, 다음 세부 사항.

    당신이 원하는 무엇을이 문제가 테이블 A에서 선택 행이 두 조건에 따라 (또는 일반적인 경우에 대한 두 개 이상의) 테이블 B에 순서대로 행이 작업을 수행하는 것입니다, 당신은 두 가지 중 하나를 수행해야합니다

    문제의이 종류는 당신이 VARCHAR에서 쉼표로 구분 된 목록을 만드는 사람들이 대신 제대로 자신의 데이터베이스를 정상화의 필드를 참조 왜, 내가 생각하는, 가장 큰 이유입니다.

    귀하의 예제에서는 태그에 두 개의 특정 조건에 일치하는 행의 존재에 따라 사용자의 행을 선택합니다.

    당신이 기술 (1) (다른 행을 테스트)를 사용할 수있는 세 가지 방법이 있습니다. 그들은 하위 쿼리를 사용하여 존재 사용하고 JOIN을 사용하고 있습니다 :

    (1A). 행의 존재를 확인 - 존재 사용하면 당신이 뭘 하려는지 일치하기 때문에 취소 (어쨌든, 내 생각에)입니다. 이것은 당신이있는 거 생성 동적 SQL, 당신은 간단한 추가를 추가하고 (성능은 물론, 고통 것) 각 태그에 대한 절을 존재하는 경우 SQL 생성을 작성하는 측면에서 더 태그 적당히 확장 성 :

    SELECT * FROM users WHERE 
      EXISTS (SELECT * FROM tags WHERE user_id = users.id AND name ='tag1') AND
      EXISTS (SELECT * FROM tags WHERE user_id = users.id AND name ='tag2')
    

    나는 이것이 명확하게 쿼리의 의도를 표현하고 생각합니다.

    도 1b는 하위 쿼리를 사용하는 것은 매우 분명하다. 이 기술은 상관 관계가 포함되지 않기 때문에 어떤 엔진이 (가 주어진 태그와 사용자 수에 부분적으로 의존) 더 잘 최적화 할 수 있습니다 서브 쿼리 :

    SELECT * FROM users WHERE 
      id IN (SELECT user_id FROM tags WHERE name ='tag1') AND
      id IN (SELECT user_id FROM tags WHERE name ='tag2') 
    

    이 옵션 1A가하는 것과 같은 방식을 확장 할 수 있습니다. 그것은 꽤 분명 (어쨌든, 나에게)도 있습니다.

    JOIN을 사용 1c는 INNER 한 번 각 태그의 사용자 테이블에 태그 테이블에 합류 포함한다. 는 동적 SQL을 생성하기 위해 더 열심히 (하지만 여전히 가능)이기 때문에 그것은뿐만 아니라 확장되지 않습니다 :

    SELECT u.* FROM users u 
         INNER JOIN tags t1 ON u.id = t1.user_id
         INNER JOIN tags t2 ON u.id = t2.user_id
      WHERE t1.name = 'tag1' AND t2.name = 'tag2'
    

    개인적으로, 나는 목표는 오히려 사용자 테이블 필터보다 레코드 집합을 가입 만드는 것입니다 것 같습니다 때문에이 상당히 적은 분명히 다른 두 옵션보다 생각합니다. 또한, 확장 성 겪고있다 당신은 내부 조인 추가하고 WHERE 절을 변경해야하기 때문이다. 참고는 태그에서 두 개의 행을 집계 조인에 걸쳐 기술 1, 2의이 기술 정렬 그것을 사용하기 때문입니다.

    ,이 일을 카운트를 사용하여 문자열 처리를 사용하는 두 가지 방법이 있습니다 :

    태그 테이블이 같은 태그가 동일한 사용자에게 두 번 적용 필요에 대해 "보호"하는 경우도 2a는 수를 사용하면 훨씬 더 쉽습니다. 당신은 (USER_ID, 이름) 태그에있는 PRIMARY KEY를 제작하거나 두 열에 고유 인덱스를 생성하여이 작업을 수행 할 수 있습니다. 행이 그런 식으로 보호되는 경우이 작업을 수행 할 수 있습니다 :

     SELECT users.id, users.user_name 
       FROM users INNER JOIN tags ON users.id = tags.user_id
       WHERE tags.name IN ('tag1', 'tag2')
       GROUP BY users.id, users.user_name
       HAVING COUNT(*) = 2
    

    이 경우에는 HAVING COUNT (*) IN 절에서 태그 이름의 수에 대하여 = 테스트 값을 일치합니다. 각 태그는 더 2의 카운트가 'tag1로'와 'tag2로'아무도의 두 인스턴스에 의해 생산 될 수 있기 때문에 한 번 이상 사용자에게 적용 할 수있는 경우가없는 작업을 수행 (및 행 자격이 곳은 안) 또는 'tag1로'플러스 'tag2로'의 한 인스턴스의 두 인스턴스 3의 수를 만들 것입니다 (사용자는 심지어 그들이해야하지만 필요하지 것이다).

    참고이 있다는 가장 확장 성 기술 성능 현명한 추가 태그 및 추가 쿼리를 추가하거나 필요에 조인하기 때문이다.

    여러 개의 태그가 허용하는 경우는 중복을 제거하기 위해 내부 집계를 수행 할 수 있습니다. 당신은 내가 위에서 보여 같은 쿼리에서이 작업을 수행 할 수 있지만, 단순 위해 나는 별도의보기에 논리를 깰거야 :

     CREATE VIEW tags_dedup (user_id, name) AS
     SELECT DISTINCT user_id, name FROM tags
    

    다음은 태그에 대한 위의 쿼리 및 대체 tags_dedup로 돌아갑니다.

    여러 행에서 문자열 목록을 생성하는 표준 SQL 집계 함수가 없기 때문에 문자열 처리를 사용하여 2b는 데이터베이스 고유의 것입니다. 이 작업을 수행하는 일부 데이터베이스는, 그러나, 확장 기능을 제공합니다. MySQL은, 당신은 GROUP_CONCAT 및 FIND_IN_SET이 작업을 수행하는 데 사용할 수 있습니다 :

    SELECT user.id, users.user_name, GROUP_CONCAT(tags.name) as all_tags
      FROM users INNER JOIN tags ON users.id = tags.user_id
      GROUP BY users.id, users.user_name
      HAVING FIND_IN_SET('tag1', all_tags) > 0 AND
             FIND_IN_SET('tag2', all_tags) > 0 
    

    참고이 매우 비효율적이며 용도는 고유의 확장을 MYSQL.

  3. ==============================

    3.그것은 분명히 '이 tag1'와 'tag2로'모든 사용자의 목록이있는 모든 사용자의 목록을 가져옵니다,하지만 같은 반응 때문에, 정확히 어떤 일을하는지 우선적으로 할 것. 그래서 우리는 좀 더 추가해야합니다 :

    그것은 분명히 '이 tag1'와 'tag2로'모든 사용자의 목록이있는 모든 사용자의 목록을 가져옵니다,하지만 같은 반응 때문에, 정확히 어떤 일을하는지 우선적으로 할 것. 그래서 우리는 좀 더 추가해야합니다 :

    사용자 (또는 users.id) 다음 수를함으로써 그룹을 수행 (*) == 다음 의지 그룹에 중복 사용자 (이 tag1와 tag2로 모두 가진 사람을 의미)와이 가진 부분이 하나 가진 사람을 제거 할 것 (2) 두 태그.

    추가이 솔루션을 피 아직 또 다른 문에 가입하지만, 솔직히 나는 확실히 빠릅니다하는 아니에요. 사람들은 성능 부분에 의견을 주시기 바랍니다 :)

    편집이 : 그냥이 쉽게 시도 할 수 있도록, 여기에 모든 일이 :

    SELECT * 
    FROM users INNER JOIN 
         tags ON tags.user_id = users.id 
    WHERE tags.name = 'tag1' OR tags.name = 'tag2'
    GROUP BY users.id
    HAVING COUNT(*) = 2
    
  4. ==============================

    4.좋아, 다시 문제를 진술.

    좋아, 다시 문제를 진술.

    "이 tag1 및 tag2로 모두 태그 테이블에 항목이있는 사용자를 찾기". 각 사용자 테이블 항목에 대한 자식 태그 테이블이 수단은 적어도 2 행

    해결 방법 1 : "이 tag1 사용자"와 "이 tag2 사용자"의 교차점

    SELECT u.*
    FROM 
        users u INNER JOIN 
        (
        SELECT user_id FROM tags WHERE name = 'tag1'
        INTERSECT
        SELECT user_id FROM tags WHERE name = 'tag2'
        ) t ON u.id = t.user_id
    

    해결 방법 2 : EXISTS

    SELECT u.*
    FROM 
        users u
    WHERE 
        EXISTS (SELECT * FROM tags t1 WHERE t1.name = 'tag1'
                         AND u.id = t1.user_id)
        AND
        EXISTS (SELECT * FROM tags t2 WHERE t2.name = 'tag2'
                         AND u.id = t2.user_id)
    

    해결 방법 3 : 가입

    SELECT u.* FROM
       users u
       INNER JOIN
       tags as t1 on t1.user_id = u.id
       INNER JOIN
       tags as t2 on t2.user_id = u.id 
    WHERE
       t1.name='tag1' AND t2.name='tag2'
    

    해결 방법 4 : IN

    SELECT u.*
    FROM 
        users u
    WHERE 
        u.id (SELECT t1.user_id FROM tags t1 WHERE t1.name = 'tag1')
        AND
        u.id (SELECT t2.user_id FROM tags t2 WHERE t2.name = 'tag2')
    

    모두가 INTERSECT 및 IN은 SQL Server의 동일한 실행 계획을 제공해야 존재

    지금이 당신이이 태그를 찾고있는 경우에 모두. 당신이 더 많은 태그를 원하는, 그들은 사용 shahkalpesh의 솔루션 너무 복잡하게된다.

    그러나, 나는 태그가 테이블에없는 및 여분의 OR 절이 필요하므로 수정할 것

    SELECT u.*
    FROM
        Users u
        Inner join
        tags t ON t.user_id = u.id
        JOIN
        @MyTags mt ON t.name = mt.name
    GROUP BY u.*
    HAVING count(tags.*) = COUNT(DISTINCT mt.name)
    
  5. ==============================

    5.

    SELECT Users.id, count(tags.*) as tagCount
    FROM Users Inner join tags
    ON tags.user_id = users.id
    WHERE tags.name='tag1' OR tags.name='tag2'
    GROUP BY Users.id
    HAVING count(tags.*) = 2
    
  6. ==============================

    6.다음을 시도해보십시오

    다음을 시도해보십시오

    SELECT * 
    FROM users u, tags t1, tags t2
    WHERE t1.user_id = t2.user_id
    AND t1.name = 'tag1'
    AND t2.name = 'tag2'
    AND t1.user_id = u.id
    

    물론, 태그의 많은 수의,이 쿼리의 성능이 심각하게 저하 될 것입니다.

  7. ==============================

    7.

    select * from users u
    where 2 = (select count(*) from tags t where t.user_id = u.id and name in ('tag1','tag2'))
    

    주어진 태그는 사용자 당 한 번 존재할 수 있다고 가정.

  8. ==============================

    8.이것을를 사용 해보세요

    이것을를 사용 해보세요

    SELECT *
    FROM users
    INNER JOIN tags ON tags.user_id = users.id
    WHERE users.id in
        (
        SELECT user_id
        FROM tags
        WHERE name IN ('tag1', 'tag2')
        GROUP BY user_id
        HAVING COUNT(*) = 2
        )
    
  9. ==============================

    9.당신은 오히려 (각 합류 기록 내에서 값을 확인합니다) 간단한 IN을 할 수있는 것보다, 두 행의 존재를 확인해야합니다. 아마 뭔가 같은 :

    당신은 오히려 (각 합류 기록 내에서 값을 확인합니다) 간단한 IN을 할 수있는 것보다, 두 행의 존재를 확인해야합니다. 아마 뭔가 같은 :

    SELECT * 
    from users
    WHERE EXISTS (SELECT NULL FROM tags WHERE tags.user_id = users.id AND tags.name = 'tag1')
      AND EXISTS (SELECT NULL FROM tags WHERE tags.user_id = users.id AND tags.name = 'tag2');
    
  10. ==============================

    10.이건 어떤가요

    이건 어떤가요

    SELECT * FROM users, tags WHERE tags.user_id = users.user_id AND tags.name = 'tag1'
    INTERSECT
    SELECT * FROM users, tags WHERE tags.user_id = users.user_id AND tags.name = 'tag2'
    
  11. ==============================

    11.시험     WHERE tags.name IN ( '이 tag1')과의 tags.name IN ( '이 tag2');

    시험     WHERE tags.name IN ( '이 tag1')과의 tags.name IN ( '이 tag2');

    슈퍼 효율적인, 그러나 많은 방법으로 아마 아니다.

  12. from https://stackoverflow.com/questions/4763143/sql-for-applying-conditions-to-multiple-rows-in-a-join by cc-by-sa and MIT license