Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql SQL如何按两列分组_Mysql_Sql - Fatal编程技术网

Mysql SQL如何按两列分组

Mysql SQL如何按两列分组,mysql,sql,Mysql,Sql,下面是一个示例表 ID FROM TO DATE 1 Number1 Number2 somedate 2 Number2 Number1 somedate 3 Number2 Number1 somedate 4 Number3 Number1 somedate 5 Number3 Number2 somedate 预期的结果是为每个唯一的to和FROM列对获取一行

下面是一个示例表

ID   FROM       TO         DATE  
1    Number1    Number2    somedate
2    Number2    Number1    somedate
3    Number2    Number1    somedate
4    Number3    Number1    somedate
5    Number3    Number2    somedate
预期的结果是为每个唯一的to和FROM列对获取一行

按ID ASC排序的结果示例

(1,Number1,Number2)
(4,Number3,Number1)
(5,Number3,Number2)
好的,我已经找到了如何通过下面的查询实现这一点

SELECT * FROM table GROUP BY LEAST(to,from), GREATEST(to,from)
然而,我无法获得每一对独特组合的最新记录


我尝试过使用order by ID desc,但它返回找到的唯一对的第一行。

我相信下面的方法会奏效,我的知识是使用Microsoft SQL Server,而不是MySQL。如果MySQL缺少其中一个,请告诉我,我将删除答案

DECLARE @Table1 TABLE(
ID int,
Too varchar(10),
Fromm varchar(10),
Compared int)

INSERT INTO @Table1 values (1, 'John','Mary', 2), (2,'John', 'Mary', 1), (3,'Sue','Charles',1), (4,'Mary','John',3)


SELECT ID, Too, Fromm, Compared
FROM @Table1 as t
INNER JOIN
(
SELECT
    CASE WHEN Too < Fromm THEN Too+Fromm
    ELSE Fromm+Too
    END as orderedValues, MIN(compared) as minComp
FROM @Table1
GROUP BY    CASE WHEN Too < Fromm THEN Too+Fromm
ELSE Fromm+Too
END
) ordered ON 
ordered.minComp = t.Compared 
AND ordered.orderedValues = 
        CASE 
            WHEN Too < Fromm 
                THEN Too+Fromm
            ELSE 
                Fromm+Too
        END
我使用了int而不是time值,但它的工作原理是一样的。它很脏,但它给了我我期望的结果


它的基本原理是使用派生查询,从中获取要获取唯一值的两列,并使用case语句将它们组合成标准格式。在本例中,前面的值按字母顺序与后面的值按字母顺序连接。使用该值获得我们正在寻找的最小值,然后连接回原始表,以再次分离出的值加上该表中的任何其他值。它假设我们聚合的值是唯一的,所以在这种情况下,如果有1个'John','Mary',2和2个'Mary','John',2,它将打破并返回这对夫妇的2条记录。

SQL fiddle由于某种原因不起作用,因此您需要帮助我来帮助您

假设以下语句有效

SELECT 
    LEAST(to,from) as LowVal, 
    GREATEST(to,from) as HighVal, 
    MAX(date) as MaxDate
FROM table 
GROUP BY LEAST(to,from), GREATEST(to,from)
那你就可以作为一个

select t.*
from 
    table t
    inner join 
        (SELECT 
            LEAST(to,from) as LowVal, 
            GREATEST(to,from) as HighVal, 
            MAX(date) as MaxDate
        FROM table 
        GROUP BY LEAST(to,from), GREATEST(to,from)
        ) v
        on t.date = v.MaxDate
        and (t.From = v.LowVal or t.From = v.HighVal)
        and (t.To = v.LowVal or t.To= v.HighVal)

这个答案最初是由 但后来我进一步研究,找到了正确的解决办法

CREATE TABLE T
    (`id` int, `from` varchar(7), `to` varchar(7), `somedate` datetime)
;

INSERT INTO T
    (`id`, `from`, `to`, `somedate`)
VALUES
    (1, 'Number1', 'Number2', '2015-01-01 00:00:00'),
    (2, 'Number2', 'Number1', '2015-01-02 00:00:00'),
    (3, 'Number2', 'Number1', '2015-01-03 00:00:00'),
    (4, 'Number3', 'Number1', '2015-01-04 00:00:00'),
    (5, 'Number3', 'Number2', '2015-01-05 00:00:00');
在MySQL 5.6.19上测试

SELECT * 
FROM 
    (
        SELECT * 
        FROM T 
        ORDER BY LEAST(`to`,`from`), GREATEST(`to`,`from`), somedate DESC
    ) X
GROUP BY LEAST(`to`,`from`), GREATEST(`to`,`from`)
结果集

我从某日到某日 3编号2编号1 2015-01-03 4编号3编号1 2015-01-04 5编号3编号2 2015-01-05 但是,这依赖于MySQL的一些可疑行为,这些行为将在将来的版本中更改。MySQL 5.7执行此查询是因为SELECT子句中的列在功能上不依赖于GROUP BY列。如果将其配置为仅接受它,则禁用了\u FULL\u GROUP\u BY,它的工作方式与以前的版本相同,但仍然不是:服务器可以从每个组中自由选择任何值,因此,除非它们相同,否则所选值是不确定的

因此,正确的答案似乎是:

SELECT T.*
FROM 
    T
    INNER JOIN 
        (
        SELECT 
            LEAST(`to`,`from`) AS LowVal, 
            GREATEST(`to`,`from`) AS HighVal, 
            MAX(somedate) AS MaxDate
        FROM T
        GROUP BY LEAST(`to`,`from`), GREATEST(`to`,`from`)
        ) v
        ON T.somedate = v.MaxDate
        AND (T.From = v.LowVal OR T.From = v.HighVal)
        AND (T.To = v.LowVal OR T.To = v.HighVal)
结果集与上面的相同,但在本例中,它保证保持这样,而在此之前,您可以根据表上的索引轻松获得行Number2、Number1的不同日期和id

它将按预期工作,直到原始数据中有两行具有完全相同的somedate和to和from

让我们添加另一行:

INSERT INTO T (`id`, `from`, `to`, `somedate`)
VALUES (6, 'Number1', 'Number2', '2015-01-03 00:00:00');
上述查询将返回2015-01-03的两行:

我从某日到某日 3编号2编号1 2015-01-03 6编号1编号2 2015-01-03 4编号3编号1 2015-01-04 5编号3编号2 2015-01-05 要解决这个问题,我们需要一个方法来只选择组中的一行。在本例中,我们可以使用唯一ID打破僵局。如果组中有多行具有相同的最长日期,我们将选择ID最大的行

最内部的子查询Groups只返回所有组,就像问题中的原始查询一样。然后,我们向这个结果集中添加一个列id,并选择属于同一组的id,该id具有最高的somedate,然后是最高的id,这是由ORDER by和LIMIT完成的。此子查询称为GroupsWithIDs。一旦我们有了所有的组和每个组的正确行id,我们就将其加入到原始表中,以获取列的其余部分以获得找到的id

最终查询

最终结果集

我从某日到某日 4编号3编号1 2015-01-04 5编号3编号2 2015-01-05 6编号1编号2 2015-01-03
这看起来真的是一个关于排除镜像结果的问题。我想你想要的是MySQL中的rank函数,我试图打开SQLFiddle,但由于某些原因,它花费了很长时间。你说的:每个唯一对的最新记录是什么意思?如果它们是独一无二的,那么它们都是最新的。你真的想只得到一条记录吗?嗨,我需要每对一条记录,但可能有像Number1-Number2、Number2-Number1、Number1-Number2、Number1-Number2这样的记录。我需要每对两个数字只得到一条最新的记录。这就像手机中的短信应用程序一样,它只显示两个号码之间通话的最后一条短信。它似乎是基于以下信息,即From=Num1,To=Num2相当于From=Num2,To=Num1。。。i、 e.您正在寻找配对,无论它们在哪列-请确认。
SELECT T.*
FROM
    (
    SELECT
        Groups.N1
        ,Groups.N2
        ,
        (
            SELECT T.id
            FROM T
            WHERE
                LEAST(`to`,`from`) = Groups.N1 AND
                GREATEST(`to`,`from`) = Groups.N2
            ORDER BY T.somedate DESC, T.id DESC
            LIMIT 1
        ) AS id
    FROM
        (
            SELECT LEAST(`to`,`from`) AS N1, GREATEST(`to`,`from`) AS N2
            FROM T 
            GROUP BY LEAST(`to`,`from`), GREATEST(`to`,`from`)
        ) AS Groups
    ) AS GroupsWithIDs
    INNER JOIN T ON T.id = GroupsWithIDs.id