Пользовательские переменные MySQL в подзапросе зависят от внешнего порядка / группы запросов? - PullRequest
0 голосов
/ 06 марта 2012

Я пытаюсь написать запрос, который найдет самое последовательное в моей базе данных. Это привело к тому, что я попробовал переменные, которые я никогда раньше не использовал.

Проблема, с которой я столкнулся, заключается в том, что мой запрос дает мне именно тот результат, который, на мой взгляд, должен, но когда я использую его в качестве подзапроса в другом запросе, все это, похоже, приводит к поту, когда я добавляю группу by / order by .

Нормально ли это, и если да, что может быть решением? Или я совершил простую ошибку?

Результаты моего подзапроса превосходны, и все, что я пытаюсь сделать во внешнем запросе, это выбрать максимум из "последовательного" столбца, который я создал. Этот столбец принимает форму

@r := IF(nFound=nThis,@r + 1,0)

т.е. он просто подсчитывает 1 для каждой строки, которая соответствует моему расположению where / order, и сбрасывается в 0, если совпадение не найдено.

Я надеялся, что результаты подзапроса будут "заданы" и просто использованы в качестве значений перед использованием в основном запросе.

Я сравниваю это, чтобы преуспеть; иногда вы хотите «вставить как значения», а не копировать все формулы, если вы понимаете, о чем я. Есть ли простой способ сделать это в MySQL?

Я задавался вопросом, может ли создание представления "укрепить" набор данных, но затем обнаружил, что переменные не допускаются в представлениях!

EDIT Хорошо, вот запрос. Это не красиво, но я взломал и попробовал много вещей. Если вы удалите последние 2 строки и функцию «MAX», все будет работать нормально, с ними будет возвращена только одна строка, а не 10 строк.

До сегодняшнего дня я никогда не использовал перекрестное соединение; практически все, что я обычно делаю, похоже, просто «ПРИСОЕДИНЯЙТЕСЬ» или «ЛЕВЫЕ СОЕДИНЕНИЯ», но сегодня это казалось необходимым.

По сути, идея состоит в том, чтобы получить максимальное количество хронологически последовательных событий, в которых присутствовал каждый человек. Не стесняйтесь вносить изменения по своему усмотрению!

"P.person <10" был просто тестом. На самом деле тысячи людей, но если бы я попытался сделать это на всех сразу, он сидел и ничего не делал целую вечность - я полагаю, перекрестное соединение становилось слишком большим? </p>

SET @r=0;

SELECT person,MAX(nConsec)  FROM (

    SELECT @r := IF(nFound=person,@r + 1,0) AS nConsec
       test.* 

    FROM (SELECT P.person, event, tDate, MAX(C.person) AS nFound
        FROM PEOPLE P
            CROSS JOIN EVENTS E
            LEFT JOIN COMPETITORS C ON C.event=E.event AND C.person = P.person

        WHERE P.person < 10
            AND tDate < NOW()

        GROUP BY P.person, event, tDate
            ORDER BY P.person ASC, tDate ASC
    ) test

) test2

GROUP BY person
    ORDER BY MAX(nConsec) DESC

РЕДАКТИРОВАТЬ 2 Хорошо, я не знаю, что, но, изменяя некоторые вещи, чтобы сохранить немного анонимности, я, кажется, непреднамеренно исправил свой собственный код ... Приятный сюрприз, но раздражает, что никакие количества ctrl-Z и ctrl-shift- Zing, кажется, показывает мне, что я делал неправильно в первую очередь!

Любое мнение / совет по поводу беспорядка, который я получил, все еще ценится. Я уверен, что могу сделать что-то умнее, если не использовать перекрестное соединение. Около 30 000 строк в «людях» и 1000 в «событиях» и около 500 конкурентов на событие, поэтому я понимаю, почему перекрестное соединение вызывает у меня проблемы (15 миллиардов строк я делаю так…). Запрос занимает 10 секунд для тех 10 идентификаторов, которые я выбрал, и 34 секунды, если я увеличу его до 1000 идентификаторов.

1 Ответ

0 голосов
/ 06 марта 2012

Что это делает для вас:

SELECT person, MAX(nConsec) AS numConsecutive FROM (
    SELECT person, COUNT(*) AS nConsec FROM (
        SELECT @r := @r + (COALESCE(@person, P.person) <> P.person) as consecutive, @person := P.person AS person FROM (
            SELECT @r := 0, @person := NULL
        ) vars
        JOIN PEOPLE P
        JOIN EVENTS E
        LEFT JOIN COMPETITORS C
            ON C.person = P.person
            AND C.event = E.event
        ORDER BY tDate
    )
    GROUP BY consecutive
)

Изменено из кода, найденного в http://www.dancewithgrenades.com/blog/mysql-consecutive-row-streaks.

Обратите внимание, что если вы рассчитываете на нескольких людей, вам нужно отслеживатьчеловек, на которого вы рассчитываете (@person переменная).Я думаю, что это должно выполняться быстрее, в основном из-за отсутствия GROUP в самом внутреннем подзапросе, который, вероятно, сильно повлиял на производительность.Если производительность все еще недостаточно высока, я бы предложил создать в PEOPLE столбец для хранения этого значения последовательной посещаемости, изменить запрос так, чтобы он работал одновременно только с одним человеком, и запустить запрос для разных групп пользователей.в разное время для обновления значения в PEOPLE.

Oh и до CROSS JOIN s - в MySQL, CROSS JOIN эквивалентно INNER JOIN эквивалентно JOIN.Вы уже использовали кросс-соединения, просто не осознавали этого.;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...