首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >SQL如何按两列分组

SQL如何按两列分组
EN

Stack Overflow用户
提问于 2015-03-03 16:49:13
回答 3查看 2.7K关注 0票数 3

贝娄是一个例子表。

代码语言:javascript
复制
ID   FROM       TO         DATE  
1    Number1    Number2    somedate
2    Number2    Number1    somedate
3    Number2    Number1    somedate
4    Number3    Number1    somedate
5    Number3    Number2    somedate

预期结果是为每一对唯一的往来列获得1行。

如果由ID命令,示例结果

代码语言:javascript
复制
(1,Number1,Number2)
(4,Number3,Number1)
(5,Number3,Number2)

好的,我已经找到了如何用下面的查询来完成这个任务。

代码语言:javascript
复制
SELECT * FROM table GROUP BY LEAST(to,from), GREATEST(to,from)

然而,我不能得到每一对独特的最新记录。

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-03-05 23:14:52

SQL小提琴不起作用是因为某些原因,因此,同时,您将需要帮助我来帮助您。

假设以下语句有效

代码语言:javascript
复制
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)

那你就可以加入

代码语言:javascript
复制
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)
票数 5
EN

Stack Overflow用户

发布于 2015-03-05 19:27:05

我相信以下内容会奏效,我的知识是使用,而不是MySQL。如果MySQL缺少这些内容,请告诉我,我将删除答案。

代码语言:javascript
复制
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,而不是时间值,但它的工作原理是一样的。这是肮脏的,但它给了我预期的结果。

它的基础是使用派生查询,其中您要获取要为其获取唯一值的两列,并使用case语句将它们组合成标准格式。在这种情况下,以前的字母与后面的值按字母顺序连在一起。使用该值获取我们正在寻找的最小值,返回原始表,使值再次分离,再加上该表中的其他内容。它假设我们正在聚合的值将是唯一的,所以在这种情况下,如果有(1,'John','Mary',2)和(2,'Mary','John',2),它就会打破和返回这对夫妇的2项记录。

票数 0
EN

Stack Overflow用户

发布于 2015-03-06 02:05:13

这个答案最初是受获取每组成组SQL结果的最大值记录启发的,但后来我进一步研究并想出了正确的解决方案。

代码语言:javascript
复制
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上测试

代码语言:javascript
复制
SELECT * 
FROM 
    (
        SELECT * 
        FROM T 
        ORDER BY LEAST(`to`,`from`), GREATEST(`to`,`from`), somedate DESC
    ) X
GROUP BY LEAST(`to`,`from`), GREATEST(`to`,`from`)

结果集

代码语言:javascript
复制
id from    to      somedate
3  Number2 Number1 2015-01-03
4  Number3 Number1 2015-01-04
5  Number3 Number2 2015-01-05

但是,这依赖于MySQL的一些不可靠的行为,这将在将来的版本中被改变。MySQL 5.7 废品查询,因为SELECT子句中的列在功能上不依赖于GROUP列。如果它被配置为接受它(ONLY_FULL_GROUP_BY被禁用),它的工作方式与以前的版本一样,但仍然不是有保证:“服务器可以自由地从每个组中选择任何值,所以除非它们是相同的,否则所选择的值是不确定的。”

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

代码语言:javascript
复制
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之前,这取决于表上有哪些索引。

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

让我们再添加一行:

代码语言:javascript
复制
INSERT INTO T (`id`, `from`, `to`, `somedate`)
VALUES (6, 'Number1', 'Number2', '2015-01-03 00:00:00');

上面的查询将返回2015-01-03的两行

代码语言:javascript
复制
id from    to      somedate
3  Number2 Number1 2015-01-03
6  Number1 Number2 2015-01-03
4  Number3 Number1 2015-01-04
5  Number3 Number2 2015-01-05

要解决这个问题,我们需要一个方法来选择组中的一行。在这个例子中,我们可以使用唯一的ID来打破领带。如果组中有多个具有相同最大日期的行,我们将选择ID最大的行。

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

最终查询

代码语言:javascript
复制
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

最终结果集

代码语言:javascript
复制
id from    to      somedate
4  Number3 Number1 2015-01-04
5  Number3 Number2 2015-01-05
6  Number1 Number2 2015-01-03
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28837339

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档