<?xml version='1.0' encoding='utf-8' ?>

<rss version='2.0' xmlns:lj='http://www.livejournal.org/rss/lj/1.0/' xmlns:atom10='http://www.w3.org/2005/Atom'>
<channel>
  <title>Замотиватор</title>
  <link>https://tsarev.dreamwidth.org/</link>
  <description>Замотиватор - Dreamwidth Studios</description>
  <lastBuildDate>Tue, 02 May 2017 12:39:18 GMT</lastBuildDate>
  <generator>LiveJournal / Dreamwidth Studios</generator>
  <lj:journal>tsarev</lj:journal>
  <lj:journaltype>personal</lj:journaltype>
<item>
  <guid isPermaLink='true'>https://tsarev.dreamwidth.org/600417.html</guid>
  <pubDate>Tue, 02 May 2017 12:39:18 GMT</pubDate>
  <title>window functions - краткая справка</title>
  <link>https://tsarev.dreamwidth.org/600417.html</link>
  <description>Уже не первый раз просят дать какую-нибудь книжку по window functions.&lt;br /&gt;Ирония состоит в том, что я такой книжки не знаю, но window functions реализовал руками когда писал СУБД.&lt;br /&gt;Попробую сейчас написать небольшую статью, прочитав которую, скорей всего, вы будете &quot;понимать&quot; window functions без мучительного вычитывания стандарта и кучи текстов разной степени понятности.&lt;br /&gt;Поехали&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Любой window function состоит из&lt;br /&gt;1) агрегационных функций&lt;br /&gt;2) over (определения окна)&lt;br /&gt;&lt;br /&gt;Агрегационные функции можно классицировать на&lt;br /&gt;1а) &quot;классические агрегаты&quot; (sum, count)&lt;br /&gt;1б) &quot;аналитические агрегаты&quot; (row_number, rank, dense_rank)&lt;br /&gt;&lt;br /&gt;Определение окна состоит из &lt;br /&gt;2а) partition by&lt;br /&gt;2b) order by&lt;br /&gt;2c) sliding window (опциональный) (rows between undounded preceding and current row как пример)&lt;br /&gt;&lt;br /&gt;Как window functions влияет на остальной запрос:&lt;br /&gt;- на выходе из window functions всегда ровно столько строчек, сколько на входе == &quot;window functions проксирует вход&quot;&lt;br /&gt;- все конструкции из определения окна влияют ТОЛЬКО на вычисления агрегаттов&lt;br /&gt;- НО! если у вас в запросе явно не указан order by (ЗА ПРЕДЕЛАМИ OVER!), то в полном соответствии с SQL стандартом, база может переупорядочить строчки так, чтобы window functions считались быстро, таким образом, порядок строчек в запросе с window functions МОЖЕТ отличаться от порядка строчек без него&lt;br /&gt;&lt;br /&gt;Теперь рассмотрим вычисления агреггатов&lt;br /&gt;Сначала применяется partition by, который группирует строчки по ключу partition by. Если в запросе нету внешнего order by (ЗА ПРЕДЕЛАМИ OVER!), то, скорей всего, строки в результате выполнения запроса будет сгруппированы (НО ЭТО НЕ ГАРАНТИРУЕТСЯ! и на это нельзя полагаться)&lt;br /&gt;&lt;br /&gt;Оба типа агреггатов (классические и аналитические) считаются по отдельным parition (с одинаковым ключем)&lt;br /&gt;Если partition by опущен - по всей выборке&lt;br /&gt;&lt;br /&gt;Ну и последнее правило.&lt;br /&gt;Всe агрегаты вычислются в рамках одного partition &lt;br /&gt;- в соответствии с порядком order by ВНУТРИ over&lt;br /&gt;- на подмножестве строк, ограниченном sliding winding.&lt;br /&gt;&lt;br /&gt;У sliding window есть такая важная штука, как current row.&lt;br /&gt;При выдаче строчки наружу из window function, current row - это текущая строчка из входа (смотрите выше правило &quot;window functions проксирует вход&quot;)&lt;br /&gt;&lt;br /&gt;sliding window бывают двух типов: rows и range&lt;br /&gt;&lt;br /&gt;&quot;rows&quot; задает относительное смещение от current row&lt;br /&gt;rows between unbounded preceding and current row - от начала текущего partition и до текущей строки&lt;br /&gt;rows between 3 preceding and 3 following - минус 3 строки назад и плюс 3 строки вперед от текущей строки&lt;br /&gt;&lt;br /&gt;range работает почти также, только он не просто &quot;считает&quot; строки, а он их &quot;группирует&quot; по ключу order by.&lt;br /&gt;Если у вас идут повторяющиеся строки, то range - это такая дополнительная их группировка, и отсчет идет по группам строк, у которых значения в колонках из order by одинаковые&lt;br /&gt;&lt;br /&gt;Собственно, все, через этот небольшой ряд правил и модель выполнения вы сможете разобраться в любом запросе с window functions и написать нужный вам&lt;br /&gt;&lt;br /&gt;Правила разбора (сжато)&lt;br /&gt;- на выходе будет столько же строк, сколько в запросе без window functions&lt;br /&gt;- разберитесь c order by - он управляет порядком строк в sliding window (и НИЧЕГО не говорит про порядок в результате)&lt;br /&gt;- разберитесь с sliding window (в случае range помните про order by)&lt;br /&gt;&lt;br /&gt;Есть один красивый пример, который иллюстриует как внутренний order by не влияет на результат выполнения запроса так, как внешний order by&lt;br /&gt;&lt;br /&gt;Если у вас есть запрос вида&lt;br /&gt;OVER (ORDER BY c ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)&lt;br /&gt;скорей всего, оптимизатор развернет этот запрос в такой:&lt;br /&gt;OVER (ORDER BY c DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)&lt;br /&gt;&lt;br /&gt;Т.е. СУБД &quot;перевернет&quot; окно, потому что preceding...current row считать проще, чем current row...following.&lt;br /&gt;Во всяком случае, SyBase именно так делает&lt;br /&gt;&lt;br /&gt;Это абсолютно легальная операция - поменять порядок order by и перевернуть окно&lt;br /&gt;Но на выходе из запроса у вас порядок строк (при отсутствии внешнего order by) будет &quot;перевернутым&quot;&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;https://www.dreamwidth.org/tools/commentcount?user=tsarev&amp;ditemid=600417&quot; width=&quot;30&quot; height=&quot;12&quot; alt=&quot;comment count unavailable&quot; style=&quot;vertical-align: middle;&quot;/&gt; comments</description>
  <comments>https://tsarev.dreamwidth.org/600417.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
</channel>
</rss>
