2012-04-20 3 views
3

Это казалось довольно простым, но это становится неудобно.ВЫБОР строк, где нет других строк, соответствующих

Предположим, что у нас есть таблица, содержащая ...

+---------+-----------+ 
| chat_id | friend_id | 
+---------+-----------+ 
| A  |   1 | 
| A  |   2 | 
| A  |   3 | 
| B  |   1 | 
| B  |   2 | 
| C  |   1 | 
| C  |   2 | 
| C  |   3 | 
| D  |   1 | 
| D  |   2 | 
| D  |   3 | 
| D  |   4 | 
| D  |   5 | 
| E  |   0 | 
| E  |   1 | 
| E  |   2 | 
| E  |   3 | 
| E  |   4 | 
| E  |   5 | 
| E  |   6 | 
| E  |   7 | 
| F  |   0 | 
| F  |   1 | 
| G  |   1 | 
| G  |   2 | 
+---------+-----------+ 

И я хочу, чтобы выбрать только те, которые имеют chat_id friend_ids 1 и 2 и никакой другой friend_id, что бы SQL будет получить B и G вернулся ?

До сих пор лучшее, что я придумал это:

SELECT DISTINCT a.chat_id, COUNT(*) 
FROM tt2 a 
LEFT JOIN tt2 b 
ON a.chat_id = b.chat_id 
AND b.friend_id NOT IN (1,2) 
WHERE a.friend_id in (1,2) 
and b.chat_id IS NULL GROUP BY a.chat_id HAVING COUNT(*) = 2; 

+---------+----------+ 
| chat_id | count(*) | 
+---------+----------+ 
| B  |  2 | 
| G  |  2 | 
+---------+----------+ 
2 rows in set (0.00 sec) 

И только в случае, если я искал chat_id где только 1,2,3 существуют ...

SELECT DISTINCT a.chat_id, COUNT(*) 
FROM tt2 a 
LEFT JOIN tt2 b 
ON a.chat_id = b.chat_id 
AND b.friend_id not in (1,2,3) 
WHERE a.friend_id IN (1,2,3) 
AND b.chat_id IS NULL 
GROUP BY a.chat_id 
HAVING COUNT (*) = 3; 

+---------+----------+ 
| chat_id | count(*) | 
+---------+----------+ 
| A  |  3 | 
| C  |  3 | 
+---------+----------+ 

Но эта таблица может стать массивной, и мне нужно, чтобы SQL был быстрым, кто-нибудь знает лучший способ?

Чтобы попытаться прояснить ... Я получаю дали кучу friend_id, и я хочу, чтобы получить chat_id, где существуют только те friend_id для этого chat_id .... с SQL быть быстрым (на SQLite)

Большое спасибо заранее!

ответ

1

Вот вариант, который должен быть в состоянии ограничить объем данных, необходимых

SELECT 
    d.chat_id, 
    COUNT(DISTINCT s.friend_id) AS matchedFriends, 
    COUNT(DISTINCT d.friend_id) AS totalFriends 
FROM tt2 AS d 
INNER JOIN tt2 AS s 
    ON s.chat_id = d.chat_id 
    AND s.friend_id IN (1,2) 
GROUP BY d.chat_id 
HAVING matchedFriends = 2 
AND totalFriends = matchedFriends 

Внутреннее соединение s убеждается, что она попадает только строки, которые получили по крайней мере один из запрошенных друзей в. В matchedFriends count проверяет, сколько из запрошенных друзей найдено.

Общее число друзей подсчитывает количество друзей в чате.

ИСПЫТАНИЕ В первую очередь, убедитесь, что есть 2 подходящих друга, а затем проверяет количество друзей в общей сложности равное количеству согласованных друзей.

Это потребует от вас предоставления как списка друзей, так и числа друзей, которых вы ищете, но должно быть эффективным.

Для повышения эффективности, имеет индекс (chat_id,friend_id) (если вы не сделали этого, при условии, что это 2-часть ПК на момент написания)

+1

Странно ли любить кого-то, с кем я никогда не встречался? ... спасибо, чувак. – jambags

0

Попробуйте это:

SELECT chat_id, GROUP_CONCAT(DISTINCT friend_id ORDER BY friend_id) AS friends 
FROM table_1 
GROUP BY chat_id 
HAVING friends = '1,2' 

Примечание: Это работает в MySQL, но я сомневаюсь, что он будет работать на SQLite.

+0

Я не думаю, что было бы целесообразно при больших объемах данных –

+0

Мне нравится ... Единственная проблема заключается в том, что он выполняет полное сканирование таблицы :-( – jambags

+0

Неизбежно, если быть честным в точках, хотя исследуйте альтернативы –

Смежные вопросы