Как получить доступ к предыдущим строкам в пользовательской скалярной функции SQL? - PullRequest
0 голосов
/ 04 октября 2019

Я хочу написать свою собственную скалярную функцию SQL, которая вычисляет среднее значение между точками данных одного столбца по переменному количеству строк на основе второго столбца. Я предполагаю, что эта функция выглядит как WINDOWMEAN(data, mileage, 100). Это вычислит среднее значение для всех data по строкам, где mileage находится в пределах 100 миль от текущей строки.

Пример:

| data | mileage | 
|  10  |  1000   |
|  15  |  1009   |
|  20  |  1056   |
|  16  |  1098   |
|  13  |  1130   |
|  14  |  1200   |

С запросом, подобнымSELECT WINDOWMEAN(data, mileage, 100) AS a FROM t, я ожидаю:

| data | mileage | a    |
|  10  |  1000   | 10   |
|  15  |  1009   | 12.5 |
|  20  |  1056   | 15   |
|  16  |  1098   | 15.25|
|  13  |  1130   | 16.33|
|  14  |  1200   | 13.5 |

a рассчитывается для каждой строки как среднее значение всех строк в пределах 100 миль от mileage, которые предшествуют текущей строке.

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

(могу предположить, что ряды упорядочены по пробегу)

Ответы [ 2 ]

0 голосов
/ 04 октября 2019

Вы можете использовать оконную функцию с соответствующим определением кадра RANGE, чтобы ограничить окно строками в пределах 100 миль от текущего:

SELECT data, mileage
     , avg(data) OVER (ORDER BY mileage RANGE BETWEEN 100 PRECEDING AND CURRENT ROW) AS a
FROM t
ORDER BY mileage;
data        mileage     a
----------  ----------  ----------
10          1000        10.0
15          1009        12.5
20          1056        15.0
16          1098        15.25
13          1130        16.3333333
14          1200        13.5

Примечания:

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

Для достижения наилучших результатов создайте индекс для t(mileage) или индекс покрытия для t(mileage, data).


Версия неоконной функции с использованием коррелированного подзапроса (также лучше работает с этим индексом):

SELECT data, mileage
     , (SELECT avg(t2.data) FROM t AS t2
        WHERE t2.mileage BETWEEN t1.mileage - 100 AND t1.mileage) AS a
FROM t AS t1
ORDER BY mileage;
0 голосов
/ 04 октября 2019

В SQL Server это возможно с помощью оконных функций ROW_NUMBER. Эта функция существует для sqlite ROW_NUMBER , но я не уверен, что она будет работать.

DECLARE @t TABLE (data int ,mileage int)

--SOME DATA
INSERT INTO @t
VALUES (10,1000),
        (15,1009),
        (20,1056)

--Replace @t by the real table name

;WITH TableWithRow(data, mileage, r)
AS
(
    SELECT data, mileage, ROW_NUMBER() OVER (ORDER BY data) 
    FROM @t
)
SELECT c.data, c.mileage, p.data previousData, p.mileage previousmileage
FROM TableWithRow c
LEFT OUTER JOIN TableWithRow p on c.r-1 = p.r

---WITHOUT CTE (bad performance)
SELECT c.data, c.mileage, p.data previousData, p.mileage previousmileage
FROM (
    SELECT data, mileage, ROW_NUMBER() OVER (ORDER BY data) r
    FROM @t
) c
LEFT OUTER JOIN (
    SELECT data, mileage, ROW_NUMBER() OVER (ORDER BY data) r
    FROM @t
) p on c.r-1 = p.r
...