Изменение вызова ORDER BY с помощью LIMIT в MySQL SELECT дает несогласованный набор строк - PullRequest
0 голосов
/ 29 октября 2011

Я был очень удивлен, обнаружив сегодня противоречивые результаты из следующего запроса 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

ResearchID является первичным ключом для таблицы Research.

Это также дает мнедругой набор, если я просто изменю порядок ORDER BY аргументов, например:

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

Не могли бы вы помочь мне понять, что происходит?

Ответил@ Кили ниже, а вот фиксированный запрос:

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 Ответ

1 голос
/ 29 октября 2011

Мой ответ здесь в значительной степени ориентирован на SQL Server, но концепция должна сохраняться и для MySQL.Если вы настроены скептически, вы должны запустить мой тест и убедиться в этом сами.

Я думаю, что проблема здесь в том, что вы хотите получить первые пять результатов по заказу вашей ResearchDate, а затем вы хотите отсортировать ТЕ в порядке убывания, Согласно PinalDave Предложение SELECT TOP X (которое является функциональным эквивалентом подмножества возможностей LIMIT) является ФИНАЛЬНЫМ этапом логической обработки запроса SELECT, поэтому он захватываетпервый X после того, как результаты уже были ORDER изд.

Если вам интересно узнать порядок обработки, я нашел это в Справочном руководстве MySQL :

Предложение HAVING применяется почти последним, непосредственно перед отправкой элементов клиенту, без оптимизации.(LIMIT применяется после HAVING.)

Вот краткий пример, который продемонстрирует проблему, которую, я думаю, вы видите, а также способы ее устранения:

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

Обратите внимание на различный набор результатов?Это проблема, которую вы решаете прямо сейчас.Вместо этого вам нужно выбрать нужные результаты в подзапросе, а затем упорядочить ТЕ во внешнем запросе.

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 ++ или любом другом языке программирования, чтобы улучшить читабельность кода.

...