Может ли функция PostgreSQL LAG () обращаться к себе? - PullRequest
0 голосов
/ 28 апреля 2020

Я только что обнаружил функцию LAG () в PostgreSQL, и я экспериментировал, чтобы увидеть, чего она может достичь. Я думал, что могу вычислить факториал с ним, и я написал

SELECT i, i * lag(factorial, 1, 1) OVER (ORDER BY i, 1) as factorial FROM generate_series(1, 10) as i;

Но онлайн IDE жалуется, что 42703 column "factorial" does not exist.

Есть ли способ, которым я могу получить доступ к результату предыдущего вызова LAG?

1 Ответ

1 голос
/ 28 апреля 2020

Вы не можете ссылаться на столбец рекурсивно в его определении.

Однако вы можете express вычислить факториал как:

SELECT i, EXP(SUM(LN(i)) OVER w)::int factorial
FROM generate_series(1, 10) i
WINDOW w AS (ORDER BY i ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW);
-- outputs:
 i  | factorial 
----+-----------
  1 |         1
  2 |         2
  3 |         6
  4 |        24
  5 |       120
  6 |       720
  7 |      5040
  8 |     40320
  9 |    362880
 10 |   3628800
(10 rows)

Postgresql поддерживает расширенный SQL функция, называемая рекурсивным запросом, которую также можно использовать для express рекурсивной таблицы факториала:

WITH RECURSIVE series AS (
  SELECT i FROM generate_series(1, 10) i
)
, rec AS (
  SELECT i, 1 factorial FROM series WHERE i = 1
  UNION ALL
  SELECT series.i, series.i * rec.factorial 
  FROM series 
  JOIN rec ON series.i = rec.i + 1
)
SELECT * 
FROM rec;

что делает EXP(SUM(LN(i)) OVER w):

Это использует математические тождества, которые:

[1]: log(a * b * c) = log (a) + log (b) + log (c)
[2]: exp (log a) = a
[combining 1&2]: exp(log a + log b + log c) = a * b * c

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

Это работает, пока умножаемые значения положительны, поскольку log не определено для 0 и отрицательных чисел. Если у вас отрицательные числа или ноль, уловка состоит в том, чтобы проверить, равно ли какое-либо значение 0, тогда вся совокупность равна 0, и проверить, является ли число отрицательных значений четным, тогда результат является положительным, иначе он отрицательный. Кроме того, вы также можете преобразовать реалы в комплексную плоскость, а затем использовать тождество Log(z) = ln(r) - iπ

что ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW делает

Это объявляет расширяющуюся оконную раму, которая включает все предыдущие строки и текущую строку.

например

when i equals 1 the values in this window frame are {1}
when i equals 2 the values in this window frame are {1,2}
when i equals 3 the values in this window frame are {1,2,3}

что такое рекурсивный запрос

Рекурсивный запрос позволяет express рекурсивная логика c с использованием SQL. Рекурсивные запросы часто используются для генерации родительско-дочерних отношений из реляционных данных (например, отчет менеджера или иерархия классификации продуктов), но они обычно могут использоваться для запроса любой древовидной структуры.

Вот SO-ответ, который я недавно написал, который иллюстрирует и объясняет некоторые возможности рекурсивных запросов .

Существует также множество полезных руководств по рекурсивным запросам. Это очень мощная sql -языковая функция, которая решает тип проблемы, которую очень трудно обойтись без рекурсии.

Надеюсь, что это даст вам более полное представление о том, что делает код. Счастливого обучения!

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