2017-02-17 11 views
3

Выборочные данныеОкно Функция: last_value (ORDER BY ... ASC) так же, как last_value (ORDER BY ... DESC)

CREATE TABLE test 
    (id integer, session_ID integer, value integer) 
; 

INSERT INTO test 
    (id, session_ID, value) 
VALUES 
    (0, 2, 100), 
    (1, 2, 120), 
    (2, 2, 140), 
    (3, 1, 900), 
    (4, 1, 800), 
    (5, 1, 500) 
; 

Текущий запрос

select 
id, 
last_value(value) over (partition by session_ID order by id) as last_value_window, 
last_value(value) over (partition by session_ID order by id desc) as last_value_window_desc 
from test 
ORDER BY id 

Я бегу в проблему с функцией last_value() окна: http://sqlfiddle.com/#!15/bcec0/2

в скрипке Я пытаюсь работать с направлением сортировки в пределах last_value() запроса.

Edit: Вопрос не: Почему я не получаю все время последнего значения и как использовать предложение кадра (unbounded preceding и unbounded following). Я знаю о разнице first_value(desc) и last_value() и проблема, что last_value() не дает вам последнее значение все время: положение кадра

по умолчанию является неограниченным, предшествующего до текущей строки. Поэтому первое значение всегда дает первую строку с предложением. Таким образом, не имеет значения, существует ли только одна строка (предложение фрейма включает только этот) или один хэндер (предложение кадра содержит все сотни). Результат всегда первый. В порядке DESC это одно и то же: DESC изменяет порядок сортировки, а затем первая строка является последним значением, независимо от того, сколько строк вы получите.

С last_value() поведение очень похоже: если у вас есть одна строка, это дает вам последнее значение предложения фрейма по умолчанию: Эта одна строка. Во второй строке предложение фрейма содержит две строки, вторая - вторая. Вот почему last_value() не дает вам последнюю строку всех строк, а только последнюю строку до текущей строки.

Но если я изменил порядок на DESC, я ожидаю, что у меня есть последняя строка из всех первых, поэтому я получаю это в первой строке, чем в последней, а второй во второй строке и так далее. Но это не результат. Зачем?

В данном примере эти результаты для first_value(), first_value(desc), last_value(), last_value(desc) и то, что я ожидал для last_value(desc):

id | fv_asc | fv_desc | lv_asc | lv_desc | lv_desc(expecting) 
----+--------+---------+--------+---------+-------------------- 
    0 | 100 |  140 | 100 |  100 | 140 
    1 | 100 |  140 | 120 |  120 | 120 
    2 | 100 |  140 | 140 |  140 | 100 
    3 | 900 |  500 | 900 |  900 | 500 
    4 | 900 |  500 | 800 |  800 | 800 
    5 | 900 |  500 | 500 |  500 | 900 

Для меня, кажется, что ORDER BY DESC флаг игнорируется в кадре по умолчанию статья last_value() звонок. Но это не входит в звонок first_value(). Поэтому мой вопрос: почему результат last_value() совпадает с last_value(desc)?

+0

Используете ли вы MS SQL Server или Postgresql? – jarlh

+0

(1) Тег с базой данных, которую вы действительно используете. (2) Есть что-то о 'last_value()', которое я не совсем помню, но я всегда использую 'first_value()'. –

+0

@jarhl Обычно я использую PostgreSQL. Но это то же самое на SQL Server –

ответ

0

Через год я получил решение:

Возьмите это заявление:

SELECT 
    id, 
    array_accum(value) over (partition BY session_ID ORDER BY id)  AS window_asc, 
    first_value(value) over (partition BY session_ID ORDER BY id)  AS first_value_window_asc, 
    last_value(value) over (partition BY session_ID ORDER BY id)  AS last_value_window_asc, 
    array_accum(value) over (partition BY session_ID ORDER BY id DESC) AS window_desc, 
    first_value(value) over (partition BY session_ID ORDER BY id DESC) AS first_value_window_desc, 
    last_value(value) over (partition BY session_ID ORDER BY id DESC) AS last_value_window_desc 
FROM 
    test 
ORDER BY 
    id 

Это дает

id window_asc  first_value_window_asc last_value_window_asc window_desc first_value_window_desc last_value_window_desc 
-- ------------- ---------------------- --------------------- ------------- ----------------------- ---------------------- 
0 {100}   100      100     {140,120,100} 140      100      
1 {100,120}  100      120     {140,120}  140      120      
2 {100,120,140} 100      140     {140}   140      140      
3 {900}   900      900     {500,800,900} 500      900      
4 {900,800}  900      800     {500,800}  500      800      
5 {900,800,500} 900      500     {500}   500      500   

array_accum показывает используемый окно. Там вы можете увидеть первое и текущее последнее значение окна.

Что показывает сложилось, план выполнения:

"Sort (cost=444.23..449.08 rows=1940 width=12)" 
" Sort Key: id" 
" -> WindowAgg (cost=289.78..338.28 rows=1940 width=12)" 
"  -> Sort (cost=289.78..294.63 rows=1940 width=12)" 
"    Sort Key: session_id, id" 
"    -> WindowAgg (cost=135.34..183.84 rows=1940 width=12)" 
"     -> Sort (cost=135.34..140.19 rows=1940 width=12)" 
"       Sort Key: session_id, id" 
"       -> Seq Scan on test (cost=0.00..29.40 rows=1940 width=12)" 

Там вы можете увидеть: Во-первых есть ORDER BY id в течение первых трех функций окна.

Это дает (как указано в вопросе)

id window_asc  first_value_window_asc last_value_window_asc 
-- ------------- ---------------------- --------------------- 
3 {900}   900      900      
4 {900,800}  900      800      
5 {900,800,500} 900      500      
0 {100}   100      100      
1 {100,120}  100      120      
2 {100,120,140} 100      140  

Тогда вы можете увидеть другой вид: ORDER BY id DESC в течение следующих трех функций окна. Этот сорт дает:

id window_asc  first_value_window_asc last_value_window_asc 
-- ------------- ---------------------- --------------------- 
5 {900,800,500} 900      500      
4 {900,800}  900      800      
3 {900}   900      900      
2 {100,120,140} 100      140      
1 {100,120}  100      120      
0 {100}   100      100       

При этой сортировке оконная функция DESC выполнена. Колонка array_accum показывает получившиеся окна:

id window_desc  
-- ------------- 
5 {500}   
4 {500,800}  
3 {500,800,900} 
2 {140}   
1 {140,120}  
0 {140,120,100} 

Результирующий (first_value DESC и) last_value DESC теперь абсолютно идентичен last_value ASC:

id window_asc  last_value_window_asc window_desc last_value_window_desc 
-- ------------- --------------------- ------------- ---------------------- 
5 {900,800,500} 500     {500}   500      
4 {900,800}  800     {500,800}  800      
3 {900}   900     {500,800,900} 900      
2 {100,120,140} 140     {140}   140      
1 {100,120}  120     {140,120}  120      
0 {100}   100     {140,120,100} 100  

Теперь мне стало ясно, почему last_value ASC равно last_value DESC. Это связано с тем, что вторая функция окна, которая дает перевернутое окно, включает ORDER.

(Последний вид плана выполнения ist последний ORDER BY заявления.)

В качестве небольшого бонуса: этот запрос показывает небольшой потенциал оптимизации: если вы сначала вызовите окна DESC, а затем ASC, вам не нужен третий вид. В данный момент он находится в правильном порядке.

2

Проблема с LAST_VALUE() заключается в том, что правила по умолчанию для оконных предложений удаляют значения, которые вы действительно хотите. Это очень тонкая проблема, и это верно во всех базах данных, которые поддерживают эту функциональность.

This приходит из блог Oracle:

Пока мы находимся на тему оконных статей, неявное и неизменного положение окна для первого и последних функций РЯДЫ МЕЖДУ неограниченной ПРЕДЫДУЩЕГО И неограниченных СЛЕДУЮЩЕГО, другими словами, все строки в нашем разделе.Для FIRST_VALUE и LAST_VALUE значение по умолчанию , но сменное предложение windowing - ROWS BETWEEN UNABUNDED PRECEDING И ТЕКУЩАЯ РУКА, другими словами, мы исключаем строки после текущего. Отбрасывания строки от нижней части списка не имеет значения, когда мы ищу первую строку в списке (FIRST_VALUE), но он делает разницу, когда мы ищем последнюю строку в списке (LAST_VALUE) поэтому вам обычно нужно либо указывать ROWS BETWEEN НЕОГРАНИЧЕННОЕ ПРЕДПОЛАГАЕМОЕ И НЕОГРАНИЧЕННОЕ СЛЕДУЮЩЕЕ при использовании LAST_VALUE или просто использовать FIRST_VALUE и отменить порядок сортировки.

Следовательно, используйте только FIRST_VALUE(). Это делает то, что вы хотите:

with test (id, session_ID, value) as (
     (VALUES (0, 2, 100), 
       (1, 2, 120), 
       (2, 2, 140), 
       (3, 1, 900), 
       (4, 1, 800), 
       (5, 1, 500) 
    ) 
    ) 
select id, 
     first_value(value) over (partition by session_ID order by id) as first_value_window, 
     first_value(value) over (partition by session_ID order by id desc) as first_value_window_desc 
from test 
order by id 
+0

Привет, спасибо, но здесь эта проблема объясняется здесь: http://dba.stackexchange.com/questions/76726/what-exactly-does-the-last-value-window -функция-но, но это был не мой вопрос. Я не просил разницы между 'first_value()' и 'last_value()', но для разницы между 'lastvalue (order by ... asc)' и 'last_value (order by ... desc)' Я буду обновите вопрос, чтобы уточнить его. –

+0

@ S-Man. , , Это проблема, с которой вы сталкиваетесь. Действительно, лучше использовать 'first_value()' все время и просто настроить порядок сортировки, чтобы получить то, что вы хотите. Определение 'last_value()' противоречит семантике оконных функций. –

0

Check how the window frame is defined. Этот пример может помочь:

select 
    id, 
    last_value(value) over (
     partition by session_id 
     order by id 
    ) as lv_asc, 
    last_value(value) over (
     partition by session_id 
     order by id desc 
    ) as lv_desc, 
    last_value(value) over (
     partition by session_id 
     order by id 
     rows between unbounded preceding and unbounded following 
    ) as lv_asc_unbounded, 
    last_value(value) over (
     partition by session_id 
     order by id desc 
     rows between unbounded preceding and unbounded following 
    ) as lv_desc_unbounded 
from t 
order by id; 
id | lv_asc | lv_desc | lv_asc_unbounded | lv_desc_unbounded 
----+--------+---------+------------------+------------------- 
    0 | 100 |  100 |    140 |    100 
    1 | 120 |  120 |    140 |    100 
    2 | 140 |  140 |    140 |    100 
    3 | 900 |  900 |    500 |    900 
    4 | 800 |  800 |    500 |    900 
    5 | 500 |  500 |    500 |    900 
+0

Привет, спасибо. Моя проблема: зачем давать столбцы lv_asc и lv_desc одинаковый результат? Для lv_desc я ожидаю заказ 140, 120, 100, 500, 800, 900, потому что окно заказывается иначе. –