Если вы используете коммерческую базу данных или PostgreSQL / Firebird / CUBRID, вы сможете воспользоваться всеми возможностями оконных функций. Мы пару раз писали об удивительности оконных функций , в частности о ROW_NUMBER (), RANK (), DENSE_RANK () .
Сегодня мы рассмотрим некоторые удивительные оконные функции, которые создают значения других строк, которые расположены до или после текущей строки.
Настройка тестовых данных
Мы собираемся сделать некоторые интересные статистические данные сегодня, используя общедоступные данные Всемирного банка . Для простоты мы проведем анализ только для стран G8 :
- Канада (Калифорния)
- Франция (FR)
- Германия (DE)
- Италия (IT)
- Япония (JP)
- Российская Федерация
- Великобритания (Великобритания)
- Соединенные Штаты (США)
А для этих стран давайте рассмотрим следующие данные за 2009-2012 годы:
ВВП на душу населения (в текущих ценах)
1
2
3
4
5
6
7
8
9
|
2009 2010 2011 2012 CA 40 , 764 47 , 465 51 , 791 52 , 409 DE 40 , 270 40 , 408 44 , 355 42 , 598 FR 40 , 488 39 , 448 42 , 578 39 , 759 GB 35 , 455 36 , 573 38 , 927 38 , 649 IT 35 , 724 34 , 673 36 , 988 33 , 814 JP 39 , 473 43 , 118 46 , 204 46 , 548 RU 8 , 616 10 , 710 13 , 324 14 , 091 US 46 , 999 48 , 358 49 , 855 51 , 755 |
Долг центрального правительства, всего (% от ВВП)
1
2
3
4
5
6
7
8
9
|
2009 2010 2011 2012 CA 51.3 51.4 52.5 53.5 DE 47.6 55.5 55.1 56.9 FR 85.0 89.2 93.2 103.8 GB 71.7 85.2 99.6 103.2 IT 121.3 119.9 113.0 131.1 JP 166.8 174.8 189.5 196.5 RU 8.7 9.1 9.3 9.4 US 76.3 85.6 90.1 93.8 |
Давайте поместим все эти данные в таблицу фактов следующим образом (синтаксис PostgreSQL):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
CREATE TABLE countries ( code CHAR (2) NOT NULL , year INT NOT NULL , gdp_per_capita DECIMAL (10, 2) NOT NULL , govt_debt DECIMAL (10, 2) NOT NULL ); INSERT INTO countries VALUES ( 'CA' , 2009, 40764, 51.3), ( 'CA' , 2010, 47465, 51.4), ( 'CA' , 2011, 51791, 52.5), ( 'CA' , 2012, 52409, 53.5), ( 'DE' , 2009, 40270, 47.6), ( 'DE' , 2010, 40408, 55.5), ( 'DE' , 2011, 44355, 55.1), ( 'DE' , 2012, 42598, 56.9), ( 'FR' , 2009, 40488, 85.0), ( 'FR' , 2010, 39448, 89.2), ( 'FR' , 2011, 42578, 93.2), ( 'FR' , 2012, 39759,103.8), ( 'GB' , 2009, 35455,121.3), ( 'GB' , 2010, 36573, 85.2), ( 'GB' , 2011, 38927, 99.6), ( 'GB' , 2012, 38649,103.2), ( 'IT' , 2009, 35724,121.3), ( 'IT' , 2010, 34673,119.9), ( 'IT' , 2011, 36988,113.0), ( 'IT' , 2012, 33814,131.1), ( 'JP' , 2009, 39473,166.8), ( 'JP' , 2010, 43118,174.8), ( 'JP' , 2011, 46204,189.5), ( 'JP' , 2012, 46548,196.5), ( 'RU' , 2009, 8616, 8.7), ( 'RU' , 2010, 10710, 9.1), ( 'RU' , 2011, 13324, 9.3), ( 'RU' , 2012, 14091, 9.4), ( 'US' , 2009, 46999, 76.3), ( 'US' , 2010, 48358, 85.6), ( 'US' , 2011, 49855, 90.1), ( 'US' , 2012, 51755, 93.8); |
Начните веселье
Люди, которые привыкли к синтаксису SQL-92, смогут быстро найти самый высокий ВВП на душу населения или самый большой долг из таблицы. Это простой запрос, как этот:
1
2
|
SELECT MAX (gdp_per_capita), MAX (govt_debt) FROM countries; |
Который вернется:
1
|
52409.00 196.50 |
Но это не интересно. Мы даже не знаем, с какими странами и с какими годами связаны эти ценности.
Стандартный SQL-92 (а также стандартный реляционный) запрос для возврата всех этих значений будет выглядеть примерно так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
SELECT 'highest gdp per capita' AS what, c1.* FROM countries c1 WHERE NOT EXISTS ( SELECT 1 FROM countries c2 WHERE c1.gdp_per_capita < c2.gdp_per_capita ) UNION ALL SELECT 'highest government debt' AS what, c1.* FROM countries c1 WHERE NOT EXISTS ( SELECT 1 FROM countries c2 WHERE c1.govt_debt < c2.govt_debt ) |
По сути, мы выбираем те строки, для которых не существует какой-либо другой строки с более высоким значением для gdp_per_capita
(первый выбор) или govt_debt
(второй выбор).
Trick! Используйте количественные предикаты сравнения!
Если ваша база данных поддерживает количественные предикаты сравнения , то вы можете написать это немного более кратко, как это:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
SELECT 'highest gdp per capita' AS what, countries.* FROM countries WHERE gdp_per_capita >= ALL ( SELECT gdp_per_capita FROM countries ) UNION ALL SELECT 'highest government debt' AS what, countries.* FROM countries WHERE govt_debt >= ALL ( SELECT govt_debt FROM countries ) |
Который по сути такой же как
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
SELECT 'highest gdp per capita' AS what, countries.* FROM countries WHERE gdp_per_capita = ( SELECT MAX (gdp_per_capita) FROM countries ) UNION ALL SELECT 'highest government debt' AS what, countries.* FROM countries WHERE govt_debt = ( SELECT MAX (govt_debt) FROM countries ) |
Выход будет:
1
2
3
4
|
what code year gdp debt ---------------------------------------------------- highest gdp per capita CA 2012 52409.00 53.50 highest government debt JP 2012 46548.00 196.50 |
Это большой объем SQL-кода для незначительных возможностей анализа, и почему-то просто не совсем правильно запрашивать одну и ту же таблицу четыре раза со всеми этими подвыборами!
FIRST_VALUE () и LAST_VALUE ()
Это где оконные функции вступают в игру, и в данном конкретном случае, FIRST_VALUE()
или LAST_VALUE()
. А сейчас давайте сосредоточимся на расчете максимального ВВП на душу населения из набора данных:
01
02
03
04
05
06
07
08
09
10
11
12
|
SELECT countries.*, FIRST_VALUE (code) OVER (w_gdp) AS max_gdp_code, FIRST_VALUE ( year ) OVER (w_gdp) AS max_gdp_year, FIRST_VALUE (gdp_per_capita) OVER (w_gdp) AS max_gdp_gdp, FIRST_VALUE (govt_debt) OVER (w_gdp) AS max_gdp_debt FROM countries WINDOW w_gdp AS ( ORDER BY gdp_per_capita DESC ) ORDER BY code, year |
Обратите внимание, как мы используем стандартное предложение SQL WINDOW
, которое в настоящее время поддерживается только PostgreSQL и Sybase SQL Anywhere.
Если вы используете Oracle или любую другую коммерческую базу данных, вы можете просто подставить ссылку на окно w_gdp
в различные предложения OVER()
для достижения эквивалентного поведения — или вы можете использовать поддержку предложений WINDOW в jOOQ и позволить jOOQ сделать то же самое для вас.
Приведенный выше запрос не даст никаких агрегатов, но он добавит значения для страны / года с самым высоким ВВП на душу населения в каждую строку таблицы:
1
2
3
4
5
6
|
each country highest per year ----------------------------------------------- CA 2009 40764.00 51.30 CA 2012 52409.00 53.50 CA 2010 47465.00 51.40 CA 2012 52409.00 53.50 CA 2011 51791.00 52.50 CA 2012 52409.00 53.50 CA 2012 52409.00 53.50 CA 2012 52409.00 53.50 |
Это чрезвычайно интересно, поскольку данные еще не агрегированы — исходный набор данных остается неизменным, пополняется новыми вычисляемыми столбцами.
Затем вы можете продолжить обработку, например, сравнить каждую страну / год с самым высоким ВВП на душу населения и с самым высоким долгом на ВВП этой страны / года:
01
02
03
04
05
06
07
08
09
10
11
|
SELECT countries.*, TO_CHAR(100 * gdp_per_capita / FIRST_VALUE (gdp_per_capita) OVER (w_gdp) , '999.99 %' ) gdp_rank, TO_CHAR(100 * govt_debt / FIRST_VALUE (govt_debt) OVER (w_debt), '999.99 %' ) debt_rank FROM countries WINDOW w_gdp AS (PARTITION BY year ORDER BY gdp_per_capita DESC ), w_debt AS (PARTITION BY year ORDER BY govt_debt DESC ) ORDER BY code, year |
Обратите внимание, как я добавил PARTITION BY
в определения окон в предложении WINDOW
. Я сделал это, потому что хочу разделить набор данных по годам, чтобы найти самые высокие значения ВВП / долга для каждого года, а не для всего набора данных.
Результат вышеупомянутого запроса может тогда быть замечен здесь:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
country percentages ------------------------------------------ CA 2009 40764 51.3 86.73 % 30.76 % CA 2010 47465 51.4 98.15 % 29.41 % CA 2011 51791 52.5 100.00 % 27.70 % CA 2012 52409 53.5 100.00 % 27.23 % DE 2009 40270 47.6 85.68 % 28.54 % DE 2010 40408 55.5 83.56 % 31.75 % DE 2011 44355 55.1 85.64 % 29.08 % DE 2012 42598 56.9 81.28 % 28.96 % FR 2009 40488 85.0 86.15 % 50.96 % FR 2010 39448 89.2 81.57 % 51.03 % FR 2011 42578 93.2 82.21 % 49.18 % FR 2012 39759 103.8 75.86 % 52.82 % GB 2009 35455 121.3 75.44 % 72.72 % GB 2010 36573 85.2 75.63 % 48.74 % GB 2011 38927 99.6 75.16 % 52.56 % GB 2012 38649 103.2 73.74 % 52.52 % IT 2009 35724 121.3 76.01 % 72.72 % IT 2010 34673 119.9 71.70 % 68.59 % IT 2011 36988 113.0 71.42 % 59.63 % IT 2012 33814 131.1 64.52 % 66.72 % JP 2009 39473 166.8 83.99 % 100.00 % JP 2010 43118 174.8 89.16 % 100.00 % JP 2011 46204 189.5 89.21 % 100.00 % JP 2012 46548 196.5 88.82 % 100.00 % RU 2009 8616 8.7 18.33 % 5.22 % RU 2010 10710 9.1 22.15 % 5.21 % RU 2011 13324 9.3 25.73 % 4.91 % RU 2012 14091 9.4 26.89 % 4.78 % US 2009 46999 76.3 100.00 % 45.74 % US 2010 48358 85.6 100.00 % 48.97 % US 2011 49855 90.1 96.26 % 47.55 % US 2012 51755 93.8 98.75 % 47.74 % |
Можно сказать, что среди стран «большой восьмерки» Канада значительно улучшилась за последние годы, сократив свой долг по сравнению с ВВП в глобальном сравнении, и в то же время увеличив ВВП на душу населения в глобальном сравнении.
Вместо того, чтобы разбивать данные по годам, мы также можем разбить их по странам и найти лучший / худший год для каждой страны за эти годы:
01
02
03
04
05
06
07
08
09
10
11
|
SELECT countries.*, TO_CHAR(100 * gdp_per_capita / FIRST_VALUE (gdp_per_capita) OVER (w_gdp), '999.99 %' ) gdp_rank, TO_CHAR(100 * govt_debt / FIRST_VALUE (govt_debt) OVER (w_debt), '999.99 %' ) debt_rank FROM countries WINDOW w_gdp AS (PARTITION BY code ORDER BY gdp_per_capita DESC ), w_debt AS (PARTITION BY code ORDER BY govt_debt DESC ) ORDER BY code, year |
Результат теперь будет выглядеть совсем иначе:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
country percentages ------------------------------------------ CA 2009 40764 51.3 77.78 % 95.89 % CA 2010 47465 51.4 90.57 % 96.07 % CA 2011 51791 52.5 98.82 % 98.13 % CA 2012 52409 53.5 100.00 % 100.00 % DE 2009 40270 47.6 90.79 % 83.66 % DE 2010 40408 55.5 91.10 % 97.54 % DE 2011 44355 55.1 100.00 % 96.84 % DE 2012 42598 56.9 96.04 % 100.00 % FR 2009 40488 85.0 95.09 % 81.89 % FR 2010 39448 89.2 92.65 % 85.93 % FR 2011 42578 93.2 100.00 % 89.79 % FR 2012 39759 103.8 93.38 % 100.00 % GB 2009 35455 121.3 91.08 % 100.00 % GB 2010 36573 85.2 93.95 % 70.24 % GB 2011 38927 99.6 100.00 % 82.11 % GB 2012 38649 103.2 99.29 % 85.08 % IT 2009 35724 121.3 96.58 % 92.52 % IT 2010 34673 119.9 93.74 % 91.46 % IT 2011 36988 113.0 100.00 % 86.19 % IT 2012 33814 131.1 91.42 % 100.00 % JP 2009 39473 166.8 84.80 % 84.89 % JP 2010 43118 174.8 92.63 % 88.96 % JP 2011 46204 189.5 99.26 % 96.44 % JP 2012 46548 196.5 100.00 % 100.00 % RU 2009 8616 8.7 61.15 % 92.55 % RU 2010 10710 9.1 76.01 % 96.81 % RU 2011 13324 9.3 94.56 % 98.94 % RU 2012 14091 9.4 100.00 % 100.00 % US 2009 46999 76.3 90.81 % 81.34 % US 2010 48358 85.6 93.44 % 91.26 % US 2011 49855 90.1 96.33 % 96.06 % US 2012 51755 93.8 100.00 % 100.00 % |
Как вы можете видеть, в большинстве стран в целом показатели ВВП в расчете на душу населения в последние годы были лучше, а также большинство стран почти строго увеличили свой собственный долг в расчете на ВВП (за исключением Германии, Франции и Италии), за исключением (США). Королевство). Россия и Канада увидели наибольший рост.
В приведенных выше примерах мы в основном использовали FIRST_VALUE()
. LAST_VALUE()
является почти противоположной функцией по отношению к упорядочению, так же как MAX()
является противоположной функцией MIN()
. Я говорю почти потому, что есть предостережение при использовании LAST_VALUE()
с ORDER BY
, потому что определение окна, которое использует ORDER BY
, неявно эквивалентно определению окна, которое использует ORDER BY
с так называемым «предложением кадра»:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
-- Find the "last" year over the complete data set -- This may not behave as expected, so always provide -- an explicit ORDER BY clause LAST_VALUE (year) OVER() -- These two are implicitly equivalent. We're not -- looking for the "last" year in the complete data -- set, but only in the frame that is "before" the -- current row. In other words, the current row is -- always the "last value" ! LAST_VALUE (year) OVER(ORDER BY year) LAST_VALUE (year) OVER( ORDER BY year ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) -- Find the "last" year in the complete data set with -- explicit ordering LAST_VALUE (year) OVER( ORDER BY year ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) |
LEAD () и LAG ()
Предыдущие функции были о сравнении значений с максимумом / минимумом ( FIRST_VALUE()
и LAST_VALUE()
) в наборе данных. Но используя оконные функции, вы также можете сравнить вещи со следующим / предыдущим значением. Или со вторым следующим / вторым предыдущим и т. Д. Используемые для этого функции называются LEAD()
(для следующего значения) и LAG()
(для предыдущего значения).
Это лучше всего объяснить на примере:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
-- Use this view as a data source containing -- all the distinct years: 2009-2012 WITH years AS ( SELECT DISTINCT year FROM countries ) SELECT FIRST_VALUE ( year ) OVER w_year AS first , LEAD ( year , 2) OVER w_year AS lead2, LEAD ( year ) OVER w_year AS lead1, year , LAG ( year ) OVER w_year AS lag1, LAG ( year , 2) OVER w_year AS lag2, LAST_VALUE ( year ) OVER w_year AS last FROM years WINDOW w_year AS ( ORDER BY year DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) ORDER BY year |
Результат теперь просто:
1
2
3
4
5
6
|
first lead2 lead1 year lag1 lag2 last ---------------------------------------------- 2012 2009 2010 2011 2009 2012 2009 2010 2011 2012 2009 2012 2009 2010 2011 2012 2009 2012 2010 2011 2012 2009 |
LEAD()
и LAG()
— действительно лучшие оконные функции, помогающие понять всю концепцию оконных функций. Для каждого года вы можете сразу увидеть, как можно сгенерировать предыдущий и следующий год в одном и том же окне и кадре с помощью очень простых вызовов функций.
Это может быть использовано, например, для поиска «соседних» стран с точки зрения ВВП на душу населения для каждой страны / года:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
SELECT year , code, gdp_per_capita, LEAD (code) OVER w_gdp AS runner_up_code, LEAD (gdp_per_capita) OVER w_gdp AS runner_up_gdp, LAG (code) OVER w_gdp AS leader_code, LAG (gdp_per_capita) OVER w_gdp AS leader_gdp FROM countries WINDOW w_gdp AS (PARTITION BY year ORDER BY gdp_per_capita DESC ) ORDER BY year DESC , gdp_per_capita DESC |
Который возвращает:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
year country runner-up leader ------------------------------------------ 2012 CA 52409 US 51755 2012 US 51755 JP 46548 CA 52409 2012 JP 46548 DE 42598 US 51755 2012 DE 42598 FR 39759 JP 46548 2012 FR 39759 GB 38649 DE 42598 2012 GB 38649 IT 33814 FR 39759 2012 IT 33814 RU 14091 GB 38649 2012 RU 14091 IT 33814 2011 CA 51791 US 49855 2011 US 49855 JP 46204 CA 51791 2011 JP 46204 DE 44355 US 49855 2011 DE 44355 FR 42578 JP 46204 2011 FR 42578 GB 38927 DE 44355 2011 GB 38927 IT 36988 FR 42578 2011 IT 36988 RU 13324 GB 38927 2011 RU 13324 IT 36988 2010 US 48358 CA 47465 2010 CA 47465 JP 43118 US 48358 2010 JP 43118 DE 40408 CA 47465 2010 DE 40408 FR 39448 JP 43118 2010 FR 39448 GB 36573 DE 40408 2010 GB 36573 IT 34673 FR 39448 2010 IT 34673 RU 10710 GB 36573 2010 RU 10710 IT 34673 2009 US 46999 CA 40764 2009 CA 40764 FR 40488 US 46999 2009 FR 40488 DE 40270 CA 40764 2009 DE 40270 JP 39473 FR 40488 2009 JP 39473 IT 35724 DE 40270 2009 IT 35724 GB 35455 JP 39473 2009 GB 35455 RU 8616 IT 35724 2009 RU 8616 GB 35455 |
Если вы хотите провести более сложный анализ, вы можете сравнить процентное соотношение между лидерами и призерами, и т. Д. В этой статье можно увидеть еще один отличный пример использования LEAD()
и LAG()
.
Вывод
Оконные функции — это невероятно мощная функция, которая доступна во всех основных коммерческих базах данных, а также в нескольких базах данных с открытым исходным кодом, таких как PostgreSQL, Firebird и CUBRID. Существовал SQL до оконных функций и SQL после оконных функций .
С jOOQ вы можете использовать оконные функции на безопасном уровне типа, как и все, что связано с SQL. Последний запрос, который мы видели, может быть написан просто так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
// Static import the generated tables and all // of jOOQ's functions from DSL import static org.jooq.example.db.postgres.Tables.*; import static org.jooq.impl.DSL.*; // Shorten the table reference by aliasing Countries c = COUNTRIES; // Specifiy a window definition WindowDefinition w_gdp = name( "w_gdp" ).as( partitionBy(c.YEAR) .orderBy(c.GDP_PER_CAPITA.desc() ) ); // Write the query as if it were native SQL System.out.println( DSL.using(conn) .select( c.YEAR, c.CODE, c.GDP_PER_CAPITA, lead(c.CODE) .over(w_gdp).as( "runner_up_code" ), lead(c.GDP_PER_CAPITA).over(w_gdp).as( "runner_up_gdp" ), lag (c.CODE) .over(w_gdp).as( "leader_code" ), lag (c.GDP_PER_CAPITA).over(w_gdp).as( "leader_gdp" ) ) .from(c) .window(w_gdp) .orderBy(c.YEAR.desc(), c.GDP_PER_CAPITA.desc()) .fetch() ); |
Вышеуказанная программа выведет
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
+----+----+--------------+--------------+-------------+-----------+----------+ |year|code|gdp_per_capita|runner_up_code|runner_up_gdp|leader_code|leader_gdp| +----+----+--------------+--------------+-------------+-----------+----------+ | 2012 |CA | 52409.00 |US | 51755.00 |{ null } | { null }| | 2012 |US | 51755.00 |JP | 46548.00 |CA | 52409.00 | | 2012 |JP | 46548.00 |DE | 42598.00 |US | 51755.00 | | 2012 |DE | 42598.00 |FR | 39759.00 |JP | 46548.00 | | 2012 |FR | 39759.00 |GB | 38649.00 |DE | 42598.00 | | 2012 |GB | 38649.00 |IT | 33814.00 |FR | 39759.00 | | 2012 |IT | 33814.00 |RU | 14091.00 |GB | 38649.00 | | 2012 |RU | 14091.00 |{ null } | { null }|IT | 33814.00 | | 2011 |CA | 51791.00 |US | 49855.00 |{ null } | { null }| | 2011 |US | 49855.00 |JP | 46204.00 |CA | 51791.00 | | 2011 |JP | 46204.00 |DE | 44355.00 |US | 49855.00 | | 2011 |DE | 44355.00 |FR | 42578.00 |JP | 46204.00 | | 2011 |FR | 42578.00 |GB | 38927.00 |DE | 44355.00 | | 2011 |GB | 38927.00 |IT | 36988.00 |FR | 42578.00 | | 2011 |IT | 36988.00 |RU | 13324.00 |GB | 38927.00 | | 2011 |RU | 13324.00 |{ null } | { null }|IT | 36988.00 | | 2010 |US | 48358.00 |CA | 47465.00 |{ null } | { null }| | 2010 |CA | 47465.00 |JP | 43118.00 |US | 48358.00 | | 2010 |JP | 43118.00 |DE | 40408.00 |CA | 47465.00 | | 2010 |DE | 40408.00 |FR | 39448.00 |JP | 43118.00 | | 2010 |FR | 39448.00 |GB | 36573.00 |DE | 40408.00 | | 2010 |GB | 36573.00 |IT | 34673.00 |FR | 39448.00 | | 2010 |IT | 34673.00 |RU | 10710.00 |GB | 36573.00 | | 2010 |RU | 10710.00 |{ null } | { null }|IT | 34673.00 | | 2009 |US | 46999.00 |CA | 40764.00 |{ null } | { null }| | 2009 |CA | 40764.00 |FR | 40488.00 |US | 46999.00 | | 2009 |FR | 40488.00 |DE | 40270.00 |CA | 40764.00 | | 2009 |DE | 40270.00 |JP | 39473.00 |FR | 40488.00 | | 2009 |JP | 39473.00 |IT | 35724.00 |DE | 40270.00 | | 2009 |IT | 35724.00 |GB | 35455.00 |JP | 39473.00 | | 2009 |GB | 35455.00 |RU | 8616.00 |IT | 35724.00 | | 2009 |RU | 8616.00 |{ null } | { null }|GB | 35455.00 | +----+----+--------------+--------------+-------------+-----------+----------+ |
Неважно, используете ли вы jOOQ для интеграции с базой данных или просто SQL — начните использовать оконные функции уже сегодня.
Ссылка: | Не упустите потрясающую мощь SQL с FIRST_VALUE (), LAST_VALUE (), LEAD () и LAG () от нашего партнера по JCG Лукаса Эдера в блоге JAVA, SQL и AND JOOQ . |