2013-11-19 3 views
1

У меня есть две таблицы:MYSQL: Найти все сообщения от определенных пользователей

таблицы сообщение (держит создатель сообщения и сообщения)
идентификатор - creatorId - глутамат

, таблицу message_viewers (говорит, кто может прочитать сообщение MsgID)
MsgID - USERID

Если я создаю сообщение, как пользователь 1 и отправить его пользователю 2 и 3 пользователя, таблицы будет выглядеть следующим образом:

tbl_message: 
1 - 1 - 'message' 
tbl_message_viewers: 
1 - 2 
1 - 3 

То, что я хочу сделать, это для получения сообщений, которые между x1 пользователями ... хп (любое количество пользователей) и только сообщения между ними.
(Пример, если пользователи 1, 2 и 3, мне нужны сообщения, где создатель 1, 2 или 3, а пользователи 2,3 для создателя = 1, 1 и 3 для создателя = 2 и 1, 2 для создателя = 3)
Я не заинтересован сообщениями между 1 и 2, или 2 и 3, или 1 и 3, но только сообщениями между 3 людьми.

Я пробовал разные подходы, такие как объединение двух таблиц в идентификатор сообщения, выбор сообщений, где creatorId IN (X, Y), а затем взятие только строк, где userId IN (X, Y) также. Может быть, что-то о группировке и подсчете строк, но я не мог понять, как это сделать.


EDIT: SQL Скрипки здесь


http://sqlfiddle.com/#!2/963c0/1

+0

это сообщение требует, по крайней мере одну строку в tbl_message_viewers? – BevynQ

+0

Да. И создатель сообщения не отправляет сообщение самому себе. – user3010549

+0

Нет, это исключительно между тремя людьми. – user3010549

ответ

3

Я думаю, что это может делать то, что вы хотите:

SELECT m.* 
FROM message m 
INNER JOIN message_viewers mv ON m.id = mv.msgId 
WHERE m.creatorId IN (1, 2, 3) 
    AND mv.userId IN (1, 2, 3) 
    AND NOT EXISTS (
    SELECT 1 
    FROM message_viewers mv2 
    WHERE mv2.msgId = mv.msgId 
     AND mv2.userId NOT IN (1, 2, 3) 
    ) 
    AND mv.userId != m.creatorId; 

ИН даст пользователям которые создавали/могли видеть, и mv.userId != m.creatorId предназначены для исключения создателя из таблицы message_viewers (как вы показали в ваших требованиях).

Edit:

С требованием только отправка сообщений между этими 3 идентификаторами, я придумал следующее:

SELECT m.id,m.creatorId,m.message 
FROM message m 
INNER JOIN message_viewers mv ON m.id = mv.msgId 
WHERE m.creatorId IN (1, 2, 3) 
    AND mv.userId IN (1, 2, 3) 
    AND mv.userId != m.creatorId 
    AND NOT EXISTS (
    SELECT 1 
    FROM message_viewers mv2 
    WHERE mv2.msgId = mv.msgId 
     AND mv2.userId NOT IN (1, 2, 3) 
    ) 
GROUP BY 1,2,3 
HAVING COUNT(*) = 2; 

sqlfiddle demo

+0

Этот запрос также возвращает все комбинации, содержащие 1, 2 и 3, но не только сообщения, отправленные и принимаемые ТОЛЬКО 1, 2 и 3 – user3010549

+0

@ user3010549. Попробуйте этот запрос. Я добавил, что не существует, чтобы исключить других зрителей. –

+0

Я получаю синтаксическую ошибку при попытке вашего запроса (кажется, не похоже на EXISTS (SELECT 1 ... – user3010549

0

Попробуйте это присоединиться и с IN()

SELECT * FROM 
tbl_message m 
JOIN tbl_message_viewers mv (m.id = mv.msgId) 
WHERE m.creatorId IN(1,2,3) AND mv.userId IN(1,2,3) 
0

Похоже, вы, возможно, хотите BETWEEN оператора:

SELECT * FROM tablename WHERE fieldname BETWEEN 1 AND 10; 
-- returns fieldname 1-10 

В этом случае, однако, BETWEEN это включено, так что вам необходимо указать != эти условия, а также:

SELECT * FROM tablename WHERE fieldname BETWEEN 1 AND 10 AND fieldname NOT IN (1, 10) 
-- returns fieldname 2-9 

http://www.w3schools.com/sql/sql_between.asp

+0

Я использовал пользователей 1, 2 и 3, но это могло быть между пользователями 1, 17 и 32. – user3010549

+0

'... WHERE fieldname МЕЖДУ 1 И 17 И имя поля МЕЖДУ 17 И 32 И ФИЛ dname NOT IN (1, 17, 32) ' –

0

это работало на оракуле

первое соединение получает количество строк для людей, которых мы не являемся int erested в секунды присоединиться получает количество строк для людей, мы заинтересованы в

в пунктах должны быть порождена какой-то динамический SQL и number_of_people также должен быть сгенерирован каким-то образом.

select msgId, count_1, count_2 
    from message tm 
     join (select ty.msgId as ty_msgId, 
        count(ty.msgId) as count_1 
       from message_viewers ty 
       where ty.userId not in (:a,:b,:c) 
      group by ty.msgId) 
     on msgId = ty_msgId 
     join (select tz.msgId as tz_msgId, 
        count(tz.msgId) as count_2 
       from message_viewers tz 
       where tz.userId in (:a,:b,:c) 
       group by tz.msgId) 
     on msgId = tz_msgId 
     where createrId in(:a,:b,:c) 
     and count_1 = 0 
     and count_2 = :number_of_people -1; 

мой SQL предпочитает этот

select msgId, count_1, count_2 
    from message tm 
     left join (select ty.msgId as ty_msgId, 
        count(ty.msgId) as count_1 
       from message_viewers ty 
       where ty.userId not in (:a,:b,:c) 
      group by ty.msgId) as X 
     on msgId = ty_msgId 
     left join (select tz.msgId as tz_msgId, 
        count(tz.msgId) as count_2 
       from message_viewers tz 
       where tz.userId in (:a,:b,:c) 
       group by tz.msgId) as Y 
     on msgId = tz_msgId 
     where createrId in(:a,:b,:c) 
     and (count_1 = 0 or count_1 is null) 
     and count_2 = :number_of_people -1; 
+0

Я попробовал этот запрос с помощью скрипта (см. мое обновленное сообщение), но он не возвращает никакого результата для пользователей 1, 2 и 3 – user3010549

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