MySQL: повторное использование пользовательских переменных в том же операторе SELECT - PullRequest
4 голосов
/ 15 марта 2012

Я выполнил поиск в stackoverflow, но не нашел точного ответа на свой вопрос, поэтому, пожалуйста, помогите мне, если сможете.

Я «хочу» построить инструкцию SQL следующим образом:

SELECT
  @tax1 := (complicated calculation formula),
  @owe := (another complicated calculation formula),
  IF(@owe=0, 0,@tax1/@owe)
FROM ...

Однако, в документации MySQL относительно пользовательских переменных , он советует против этого сказать:

Как правило, вы никогда не должны присваивать значение пользовательской переменной и читать значение в одном и том же выражении. Вы можете получить ожидаемые результаты, но это не гарантировано. Порядок вычисления для выражений с участием пользовательских переменных не определен и может изменяться в зависимости от элементов, содержащихся в данном выражении; Кроме того, этот порядок не гарантируется одинаковым между выпусками MySQL Server. В SELECT @a, @a: = @ a + 1, ... вы можете подумать, что MySQL сначала вычислит @a, а затем выполнит присваивание. Однако изменение оператора (например, путем добавления предложения GROUP BY, HAVING или ORDER BY) может привести к тому, что MySQL выберет план выполнения с другим порядком оценки.

Моя цель состоит в том, чтобы избежать копирования и вставки этих очень сложных формул, потому что это ухудшает читабельность, и, если формула меняется каждый раз, я должен гарантировать, что она изменяется во всех местах - НО я знаю, делая это, она ' все будет работать нормально.

Кроме того, я знаю, что ALIAS не работает, потому что псевдонимы работают только в предложениях GROUP BY, HAVING и ORDER.

Я читал в некоторых других публикациях, чтобы сначала выполнить подзапрос, чтобы сначала вычислить @ tax1 и @owe, а затем использовать другой запрос, чтобы объединить результаты. НО я думаю, что производительность может быть менее эффективной, чем простое копирование и вставка этих формул на месте.

У кого-нибудь есть предложения, что они будут делать? Или я застрял с выбором между удобочитаемостью и производительностью?

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 07 декабря 2013

Да, единственный способ сделать это в SQL без пользовательских переменных - написать подзапрос производной таблицы .Затем вы можете использовать псевдонимы столбцов для ссылки на результаты этих сложных выражений:

SELECT tax1, owe, IF(owe=0, 0,tax1/owe) AS ratio
FROM (
  SELECT
    (complicated calculation formula) AS tax1,
    (another complicated calculation formula) AS owe
  FROM ...
) AS _sub

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

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

0 голосов
/ 07 декабря 2013

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

Это пример:

MySQL Составьте список лучших X записей по категориям, объединяя каждую запись с ее предыдущим отличием

create table if not exists 
        closemovers engine=memory 
select 
          code 
        , date 
        , close 
        , rank 
        , prevclose 
        , sign 
        , cumm 
from 
        ( select 
                  `code` 
                , `date` 
                , `close` 
                , @rank := if( @code = code , @rank + 1 , 1) as rank 
                , @prevclose := if( @code = code , cast( @prclose as decimal(10,3) ), null) as prevclose 
                , if(@code = code, sign( @prclose - close), NULL) as sign 
                , @cumm := if(@code = code and @psign = sign(@prclose - close), @cumm + 1 , 1) as cumm
                , @psign := sign(@prclose - close) 
                , @code := code
                , @prclose := close 
        from 
            companyhistory 
        order by 
            code, date 
         ) as ranked 
 join 
        pricefeed 
                using (code) 
where 
        rank < 10 
        and sign is not null ;

Я надеюсь, что это может дать вам подсказку

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