Предположим, у нас есть база данных для приложения чата:

CREATE TABLE Users (uid int PRIMARY KEY, name text, phone text );

CREATE TABLE Messages (recipient int REFERENCES Users(uid), sender int 
REFERENCES Users(uid), time timestamp NOT NULL, message text NOT NULL, 
PRIMARY KEY (recipient, sender, time));

Я хочу найти все сообщения, которые были отправлены как минимум между двумя разными парами пользователей. Например, если сообщение «Hello» было отправлено от пользователя 1 к пользователю 2, а также от пользователя 75 к пользователю 83, то оно должно быть показано в результате. Однако, если он был отправлен только между Пользователем 1 и Пользователем 2, он не должен отображаться в результате.

Я рассматриваю группирование всех сообщений, которые появляются как минимум два раза, следующим образом:

SELECT message 
FROM Messages 
GROUP BY message 
HAVING COUNT(*) > 1

Однако это не поможет, поскольку одна и та же пара пользователей могла отправлять одно и то же сообщение снова и снова. Можно ли группировать по отправителю, получателю и сообщению одновременно? Если да, что это даст мне в результате?

Кроме того, есть ли способ, которым я мог бы легко заполнить эти две таблицы случайными значениями и отработать запросы самостоятельно, чтобы проверить их?

Заранее спасибо!

0
MJ13 2 Май 2019 в 13:56

4 ответа

Лучший ответ

Да, сначала начните с группировки user1, user2 и сообщения. Это дает вам уникальное сообщение для каждой пары:

SELECT case when recipient > sender then recipient else sender end user1,
       case when recipient > sender then sender else recipient end user2,
       message 
FROM Messages 
GROUP BY user1, user2, message

Затем из этой группы результатов по Message и возвращаем только счетчик больше 1. Вы можете использовать вложенный запрос, чтобы сделать это:

SELECT message, COUNT(message) 
FROM (SELECT case when recipient > sender then recipient else sender end user1,
            case when recipient > sender then sender else recipient end user2,
            message 
     FROM Messages 
     GROUP BY user1, user2, message) PairMessages 
GROUP BY message 
HAVING COUNT(message) > 1

Может быть, начать с этого в качестве теста:

INSERT INTO Users VALUES (1,'john',1111111111)
INSERT INTO Users VALUES (2,'paul',2222222222)
INSERT INTO Users VALUES (75,'george',7575757575)
INSERT INTO Users VALUES (83,'ringo',8383838383)
INSERT INTO Messages VALUES (2,1,GETDATE(),'Yesterday')
INSERT INTO Messages VALUES (1,2,GETDATE(),'hello')
INSERT INTO Messages VALUES (75,83,GETDATE(),'yellow')
INSERT INTO Messages VALUES (75,83,GETDATE(),'hello')

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

Изменить: я обновил выше с правильным ответом, чтобы показать, что каждая пара пользователей уникальна для каждого сообщения. Кроме того, может быть хорошей идеей создать groupID для каждой пары пользователей. Затем вы можете добавить столько пользователей, сколько вы хотите к этому groupID. Смотрите здесь для идеи: http://sqlfiddle.com/#!9/fbc2e2/3

1
thewallrus 6 Май 2019 в 19:20

Самый простой способ добиться этого - использовать следующий запрос:

select message, count(*)
from Messages
group by message
HAVING COUNT(distinct least(recipient, sender), greatest(recipient, sender)) > 1

Это улучшает запрос forpas, добавляя количество раз, когда это сообщение использовалось.

1
Michele La Ferla 6 Май 2019 в 06:12

Вы можете использовать EXISTS для фильтрации:

SELECT m.message 
FROM Messages m
WHERE EXISTS (SELECT 1
              FROM Messages m2
              WHERE m2.message = m.message AND
                    m2.recipient NOT IN (m.recipient, m.sender) AND
                    m2.sender NOT IN (m.recipient, m.sender)
             )       
GROUP BY m.message ;

EXISTS проверяет, что другая строка с тем же сообщением имеет другую пару пользователей.

0
Gordon Linoff 4 Май 2019 в 16:29