Условная логика на псевдонимах SQL - PullRequest
1 голос
/ 14 февраля 2010

У меня есть SQL-запрос, который объединяет историческую информацию о цене. Он не особо чистый и, вероятно, может быть оптимизирован. Одна из причин этого заключается в том, что я использую подзапрос, чтобы получить «предыдущее» значение цены через подзапрос и назначить его псевдониму «last_value». В идеале я хотел бы иметь возможность использовать этот псевдоним в предложении WHERE, а не выполнять повторный поиск.

Я понимаю, почему это невозможно (запросы SQL разбираются справа налево, а псевдонимы применяются до того, как данные передаются обратно, насколько я понимаю). Я просто хотел опубликовать здесь, чтобы спросить, можно ли сделать что-то подобное, используя альтернативные средства.

В частности, я бы хотел вычислить процентную разницу между p.value (текущим значением) и last_value (последним значением) с помощью SQL, а не делать это на прикладном уровне.

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

Я использую MySQL.

$sql = "SELECT 
                t.*,
                p.value,
                p.timestamp,
                (SELECT 
                    value 
                FROM 
                    prices 
                WHERE 
                    prices.id = p.id AND 
                    prices.country=':country' AND 
                    prices.timestamp < p.timestamp
                ORDER BY 
                    prices.timestamp DESC 
                LIMIT 1) AS last_value
            FROM
                prices AS p,
                titles AS t
            WHERE
                t.row_id = p.id AND
                p.country = ':country' AND
                p.current = 1 AND
                (SELECT 
                    value 
                FROM 
                    prices 
                WHERE 
                    prices.id = p.id AND 
                    prices.country=':country' AND 
                    prices.timestamp < p.timestamp
                ORDER BY 
                    prices.timestamp DESC 
                LIMIT 1) IS NOT NULL
            ORDER BY
                p.timestamp DESC
            LIMIT :offset, :limit";

Ответы [ 2 ]

2 голосов
/ 14 февраля 2010

Я никогда не использовал MySQL, но в SQL Server я бы сделал что-то вроде этого:

SELECT (last.value - current.value) / last.value AS percentage
FROM (SELECT .... ) AS last
INNER JOIN (SELECT ...) AS current
ON last.PK = current.PK

Возможно, он все еще работает в MySQL, так как я полагаю, что он в значительной степени стандартный SQL-92 Вот ссылка на документы MySQL по этому вопросу: http://dev.mysql.com/doc/refman/5.0/en/unnamed-views.html

0 голосов
/ 16 февраля 2010

У Александра была правильная идея (я, к сожалению, не могу проголосовать за вас, потому что с тех пор я зарегистрировался с надлежащей учетной записью Stackoverflow). SQL, который я использовал в итоге:

SELECT
                    current.*,
                    last.value AS last_value
                FROM
                    (SELECT
                        t.*,
                        p.id AS p_id,
                        p.value,
                        p.timestamp
                    FROM
                        prices AS p,
                        titles AS t
                    WHERE
                        t.row_id = p.id AND
                        p.country = ':country' AND
                        p.current = 1
                    ) current
                INNER JOIN
                    (SELECT 
                        prices.* 
                    FROM 
                        prices 
                    WHERE 
                        prices.country = ':country' AND
                        prices.current = 0
                    ORDER BY
                        prices.timestamp DESC) last 
                    ON 
                        last.id = current.p_id AND 
                        last.timestamp < current.timestamp
                GROUP BY
                    current.row_id
                ORDER BY
                    current.timestamp DESC,
                    current.name ASC
                LIMIT :offset, :limit
...