2013-12-08 1 views
2

Этот вопрос основан на не очень тривиальном вопросе How to remove two duplicate column. Я уже предложил решение по этому вопросу, но я думаю, что есть более подходящее и элегантное решение, чем у меня.Как правильно исключить строки со ссылками друг на друга?

Существует таблица сообщений с колонками msg_id, from, to.
И у нас есть эти данные в нем:

msg_id from to 
---------------- 
1  46  0 
2  46  18 
3  46  50 
4  46  39 
5  46  11 
6  11  46 
7  46  12 
8  46  56 
9  46  11 

Мы должны исключить строки с разговорами, в которых имеется более одного сообщения (например, строки с msg_id = 5, 6 и 9) и в то же время необходимо оставить первую строку в выходе из этих строк. В общем выходе должно быть, как это (примечание: без msg_id = 6 и msg_id = 9):

msg_id from to 
---------------- 
1  46  0 
2  46  18 
3  46  50 
4  46  39 
5  46  11 
7  46  12 
8  46  56 

Мое решение:

select distinct pm.`from`, pm.`to` 
from `tsk_private_message` pm 
left join 
    (select distinct pm.`from`, pm.`to` 
    from `tsk_private_message` pm 
    inner join `tsk_private_message` pm2 
    on (pm.`to` = pm2.`from`) and (pm2.`to` <> pm.`from`)) a 
    using (`from`, `to`) 
where a.`from` is null; 

Я просто искать ненужные строки из этих разговоров через подзапрос и «вычесть» результат основной стол. Как вы думаете? Есть ли более элегантное и более простое решение? Мне просто не нравится этот хитрый код.

Вот SQL Fiddle

ответ

1
SELECT mx.msg_id, pm.ffrom, pm.tto 
FROM tsk_private_message pm 
WHERE NOT EXISTS (
    SELECT * FROM tsk_private_message nx1 
    WHERE nx1.ffrom = pm.ffrom AND nx1.tto = pm.tto 
    AND nx1.msg_id < pm.msg_id 
    ) 
AND NOT EXISTS (
    SELECT * FROM tsk_private_message nx2 
    WHERE nx2.ffrom = pm.tto AND nx2.tto = pm.ffrom 
    AND nx2.msg_id < pm.msg_id 
    ); 

Примечание: Я переименовал to и from столбцы tto и ffrom, потому что к и из как ключевые слова в SQL, и я не люблю кавычки идентификаторы.

Extra: sqlfiddle (courtesy of Alexander Myshov)

+1

[SQL Fiddle] (http://sqlfiddle.com/#!2/81ef4/20) как дополнение к ответу –

1
SELECT * 
FROM 
    tsk_private_message INNER JOIN (
    SELECT MIN(id) min_id 
    FROM tsk_private_message 
    GROUP BY 
     LEAST(`from`, `to`), 
     GREATEST(`from`, `to`)) min_msg 
    ON tsk_private_message.id = min_msg.min_id 
ORDER BY 
    id 

Пожалуйста, смотрите скрипку here.

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