[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.다시 태그 테이블에 가입 할 수 있습니다.
다시 태그 테이블에 가입 할 수 있습니다.
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.먼저 일반적으로이 문제에 대한하자의 이야기, 다음 세부 사항.
먼저 일반적으로이 문제에 대한하자의 이야기, 다음 세부 사항.
당신이 원하는 무엇을이 문제가 테이블 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.그것은 분명히 '이 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.좋아, 다시 문제를 진술.
좋아, 다시 문제를 진술.
"이 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.
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.다음을 시도해보십시오
다음을 시도해보십시오
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.
select * from users u where 2 = (select count(*) from tags t where t.user_id = u.id and name in ('tag1','tag2'))
주어진 태그는 사용자 당 한 번 존재할 수 있다고 가정.
-
==============================
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.당신은 오히려 (각 합류 기록 내에서 값을 확인합니다) 간단한 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.이건 어떤가요
이건 어떤가요
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.시험 WHERE tags.name IN ( '이 tag1')과의 tags.name IN ( '이 tag2');
시험 WHERE tags.name IN ( '이 tag1')과의 tags.name IN ( '이 tag2');
슈퍼 효율적인, 그러나 많은 방법으로 아마 아니다.
from https://stackoverflow.com/questions/4763143/sql-for-applying-conditions-to-multiple-rows-in-a-join by cc-by-sa and MIT license
'SQL' 카테고리의 다른 글
[SQL] 파일 시스템 대 데이터베이스의 이미지 (0) | 2020.05.08 |
---|---|
[SQL] SQL 스크립트는 잘못된 이메일 주소를 찾을 수 (0) | 2020.05.08 |
[SQL] 싱글 부모 엔터티와 코어 데이터 성능 (0) | 2020.05.08 |
[SQL] MySQL의에서 보관 IPv6 주소 (0) | 2020.05.08 |
[SQL] SQL 쿼리는 지정된 키의 각 인스턴스에 대해 가장 최근의 행을 얻을 수 있습니다 (0) | 2020.05.08 |