在MySQL SELECT中使用LIMIT更改ORDER BY子句会产生不一致的行集

时间:2011-10-29 14:52:43

标签: mysql sql sql-order-by

我很惊讶今天在以下MySQL查询中找到了不一致的结果:

SELECT Research.Focus, Research.Media, Country.Name, GROUP_CONCAT(DISTINCT AskMethod.Name ORDER BY ResearchAskMethod.MethodID SEPARATOR ', ') as AskMethodName, Research.ResearchDate, Research.ResearchID FROM AskMethod INNER JOIN ((Country INNER JOIN Research ON Country.CountryID = Research.CountryID) INNER JOIN ResearchAskMethod ON Research.ResearchID = ResearchAskMethod.ResearchID) ON AskMethod.MethodID = ResearchAskMethod.MethodID WHERE Research.ResearchID=ResearchAskMethod.ResearchID AND Research.ResearchDate=1996 GROUP BY Research.ResearchID ORDER BY Country.Name, Research.Media, AskMethodName, Research.ResearchDate DESC LIMIT 0, 5;

这个查询给了我5行:ResearchID:18,17,10,7,13。

如果我只是将DESC添加到第一个ORDER BY参数,以便它变为:

...ORDER BY Country.Name DESC, Research.Media...

此查询为我提供了另外一组5行:ResearchID:8,14,9,13,7

ResearchIDResearch表的主键。

如果我只是更改ORDER BY参数的顺序,它也会给我一个不同的集合,例如:

... ORDER BY Research.Media, Country.Name, AskMethodName...

你能帮我理解发生了什么吗?

@Kiley在下面回答,这是固定查询:

SELECT * 
FROM (
    SELECT Research.Focus, Research.Media, Country.Name, GROUP_CONCAT( DISTINCT ValMethod.Name
    ORDER BY ResearchValMethod.MethodID
    SEPARATOR  ', ' ) AS ValMethodName, Research.ResearchDate, Research.ResearchID
    FROM ValMethod
    INNER JOIN (
        (
        Country
        INNER JOIN Research ON Country.CountryID = Research.CountryID
        )
    INNER JOIN ResearchValMethod ON Research.ResearchID = ResearchValMethod.ResearchID
    ) ON ValMethod.MethodID = ResearchValMethod.MethodID
    WHERE Research.ResearchID = ResearchValMethod.ResearchID
    AND Research.ResearchDate = 1996
    GROUP BY Research.ResearchID
    ORDER BY Country.Name, Research.Media, ValMethodName, Research.ResearchDate
) AS Result
ORDER BY Result.Name, Result.Media, ValMethodName, Result.ResearchDate DESC

1 个答案:

答案 0 :(得分:1)

我的回答主要针对SQL Server,但这个概念也适用于MySQL。如果你持怀疑态度,你应该运行我的测试并亲自验证。

我认为这里的问题是你想要你的ResearchDate订购前五个结果,然后你想按降序排序。 According to PinalDave SELECT TOP X子句(它是LIMIT能力子集的功能等同物)是SELECT查询逻辑处理中的最后一步,所以它在结果已经X后,抓取第一个ORDER

如果您对处理订单感到好奇,我在MySQL Reference Manual上找到了这个:

  

HAVING子句几乎在最后一次应用,就在项目发送到客户端之前,没有优化。 (在HAVING之后应用LIMIT。)

以下是一个快速示例,它将演示我认为您正在看到的问题,以及如何解决它:

CREATE TABLE [Test] (
    Number INT PRIMARY KEY
);

INSERT INTO [Test] VALUES (1);
INSERT INTO [Test] VALUES (2);
INSERT INTO [Test] VALUES (3);
INSERT INTO [Test] VALUES (4);
INSERT INTO [Test] VALUES (5);
INSERT INTO [Test] VALUES (6);
INSERT INTO [Test] VALUES (7);
INSERT INTO [Test] VALUES (8);
INSERT INTO [Test] VALUES (9);
INSERT INTO [Test] VALUES (10);

这样可以设置您的数据。现在运行以下查询并检查输出:

SELECT TOP 5 * FROM Test ORDER BY Number;

在MySQL中:

SELECT * FROM Test ORDER BY Number LIMIT 5;

此查询将生成以下结果集:

1
2
3
4
5

现在,看看差异:

SELECT TOP 5 * FROM Test ORDER BY Number DESC;

在MySQL中:

SELECT * FROM Test ORDER BY Number DESC LIMIT 5;

产地:

10
9
8
7
6

注意不同的结果集?这就是你现在遇到的问题。相反,您需要做的是在子查询中选择所需的结果,然后在外部查询中订购THOSE。

SELECT * FROM (
    SELECT TOP 5 * FROM Test ORDER BY Number
) AS MyTest ORDER BY Number DESC

最后,在MySQL中:

SELECT * FROM (
    SELECT * FROM Test ORDER BY Number LIMIT 5
) AS MyTest ORDER BY Number DESC

结果?

5
4
3
2
1

我认为这就是你要找的东西。

我不是MySQL的人,但我也发现LIMIT的一些简洁功能允许你指定返回的结果集的上限和下限,所以如果你确切地知道你的表中预期有多少行(你可能没有,但我认为这可能值得一提,因为你的理解),你可能会这样(只有MySQL的例子:)

SELECT * FROM Test ORDER BY Number DESC LIMIT 6, 10

我会根据我在此处提供的示例来解决您的查询,但由于格式有点差,因此有点难以分辨出...:

SELECT * FROM (SELECT Research.Focus, Research.Media, Country.Name, GROUP_CONCAT(DISTINCT AskMethod.Name ORDER BY ResearchAskMethod.MethodID SEPARATOR ', ') as AskMethodName, Research.ResearchDate, Research.ResearchID FROM AskMethod INNER JOIN ((Country INNER JOIN Research ON Country.CountryID = Research.CountryID) INNER JOIN ResearchAskMethod ON Research.ResearchID = ResearchAskMethod.ResearchID) ON AskMethod.MethodID = ResearchAskMethod.MethodID WHERE Research.ResearchID=ResearchAskMethod.ResearchID AND Research.ResearchDate=1996 GROUP BY Research.ResearchID ORDER BY Country.Name, Research.Media, AskMethodName, Research.ResearchDate) AS Result ORDER BY Country.Name, Research.Media, AskMethodName, Research.ResearchDate DESC;

为了记录,我建议稍微清理一下您的查询布局,以便更容易理解。使用断行,空格等,就像在PHP或C#或Java或C ++或任何其他编程语言中一样,以提高代码的可读性。