mysql或postgres中两列的独特组合

时间:2015-06-03 13:30:19

标签: mysql sql postgresql

我必须获得两列的独特组合。

例如,如果值是:

sender_id   recipient_id   created_at

    1            2         10/11/2014
    2            1         10/12/2014 
    1            2         10/13/2014
    1            3         10/14/2014

我希望输出为:

sender_id   recipient_id   created_at

    1            3         10/14/2014
    1            2         10/13/2014

我写了这个查询:

SELECT DISTINCT ON (sender_id, recipient_id) *
FROM "messages"
WHERE ((recipient_id = 1 and recipient_delete = false) 
    or (sender_id = 1 and sender_delete = false))
ORDER BY sender_id, recipient_id, created_at DESC

但它输出了这个:

sender_id   recipient_id   created_at

    1            3         10/14/2014
    2            1         10/12/2014 
    1            2         10/13/2014

2 个答案:

答案 0 :(得分:3)

DISTINCT ON的初步想法很好,但是:

  • 它适用于postgres但不适用于mysql,DISTINCT ON()是PostgreSQL的非标准扩展。
  • ON()必须应用于表达式,其中(1,2)和(2,1)是等价的。

因此,对postgres应该有效并且有效的密切查询是:

SELECT DISTINCT ON (pair) *,
    CASE WHEN sender_id<recipient_id
      THEN (sender_id,recipient_id)
      ELSE (recipient_id,sender_id)
    END AS pair
FROM messages
ORDER BY pair, created_at DESC ;

答案 1 :(得分:2)

获取所有对的一个选项,无论它们是向前还是向后(例如(1,2)==(2,1)),都要从中选择LEAST()GREATEST()每行,然后选择不同的值。使用此查询:

SELECT DISTINCT LEAST(sender_id, recipient_id), GREATEST(sender_id, recipient_id)
FROM myTable;

您将获得以下输出:

| 1 | 2 |
| 1 | 3 |

一旦你有了这个,你可以通过这些来获得每对的最大日期:

SELECT LEAST(sender_id, recipient_id), GREATEST(sender_id, recipient_id), MAX(created_at)
FROM myTable
GROUP BY LEAST(sender_id, recipient_id), GREATEST(sender_id, recipient_id);

此查询将为您提供每对所需的数据,但不会返回原始表中的实际行。如果有一行格式为| 2 | 1 | 2014-10-15 |,则此查询将返回| 1 | 2 | 2014-10-15

要获取表格中的原始行,您需要JOIN,条件是所有必要的列都匹配:

SELECT m.*
FROM myTable m
JOIN(
  SELECT LEAST(sender_id, recipient_id) AS least, 
    GREATEST(sender_id, recipient_id) AS greatest,
    MAX(created_at) AS maxDate
  FROM myTable
  GROUP BY LEAST(sender_id, recipient_id), GREATEST(sender_id, recipient_id)) tmp
ON tmp.least = LEAST(m.sender_id, m.recipient_id) AND tmp.greatest = GREATEST(m.sender_id, m.recipient_id) AND tmp.maxDate = m.created_at;

以下是符合预期结果的SQL Fiddle示例。