---
title: "ClickHouse® tips #8: Generating time-series on ClickHouse®"
excerpt: "ClickHouse® doesn't have a generate_series function yet, but you can achieve the same with other functions. Learn how here. Part 8."
authors: "Xoel Lopez"
categories: "The Data Base"
createdOn: "2023-09-25 00:00:00"
publishedOn: "2021-06-01 00:00:00"
updatedOn: "2023-06-29 00:00:00"
status: "published"
---

<p>You may be wondering if <code>generate_series</code> exists on ClickHouse® like it does on Postgres. The bad news is that it doesn’t (yet); the good news is this post will teach you how to do on ClickHouse® everything you can do on Postgres with <code>generate_series</code>, and more.</p><p>First, let’s see how the <a href="https://clickhouse.tech/docs/en/sql-reference/table-functions/numbers/"><code>numbers</code></a> function works on ClickHouse®. It generates integers between a minimum value (0 by default) and a maximum value that you pass to it:</p><figure class="kg-card kg-embed-card"><iframe loading="lazy" width="100%" src="https://snippets.tinybird.co/endpoint?code=SELECT%20%2A%20FROM%20numbers%2810%29%0A&amp;language=Tinybird&amp;title=Numbers%20produces%20rows&amp;run=run&amp;token=p.eyJ1IjogIjdmOTIwMmMzLWM1ZjctNDU4Ni1hZDUxLTdmYzUzNTRlMTk5YSIsICJpZCI6ICI3N2NiMDljOS1hYjVjLTQ2MzYtYTA4Yi00ZDYwNDQwMzUyZTYifQ.XhZPypxjhaeJbdJzNozOKmKPbFqM9CWkAil8WiXFaAE"></iframe></figure><p>A similar result can be obtained with the <a href="https://clickhouse.tech/docs/en/sql-reference/functions/array-functions/#rangeend-rangestart-end-step"><code>range</code></a> function, that returns arrays. If we only provide an argument, it behaves like <code>numbers</code>. And with <code>range</code> we can also specify a <code>start</code>, <code>end</code> and <code>step</code>:</p><figure class="kg-card kg-embed-card"><iframe loading="lazy" width="100%" src="https://snippets.tinybird.co/endpoint?code=SELECT%20range%2810%29%2C%20range%280%2C%2010%2C%202%29%0A&amp;language=Tinybird&amp;title=Range%20produces%20arrays&amp;run=run&amp;token=p.eyJ1IjogIjdmOTIwMmMzLWM1ZjctNDU4Ni1hZDUxLTdmYzUzNTRlMTk5YSIsICJpZCI6ICI3N2NiMDljOS1hYjVjLTQ2MzYtYTA4Yi00ZDYwNDQwMzUyZTYifQ.XhZPypxjhaeJbdJzNozOKmKPbFqM9CWkAil8WiXFaAE"></iframe></figure><p>This, combined with <code>arrayJoin</code> lets us do the same as <code>generate_series</code>:</p><figure class="kg-card kg-embed-card"><iframe loading="lazy" width="100%" src="https://snippets.tinybird.co/endpoint?code=SELECT%20arrayJoin%28range%280%2C%2010%2C%202%29%29%20AS%20number%0A&amp;language=Tinybird&amp;title=Range%20of%20integers%20using%20start%2C%20end%20and%20step&amp;run=run&amp;token=p.eyJ1IjogIjdmOTIwMmMzLWM1ZjctNDU4Ni1hZDUxLTdmYzUzNTRlMTk5YSIsICJpZCI6ICI3N2NiMDljOS1hYjVjLTQ2MzYtYTA4Yi00ZDYwNDQwMzUyZTYifQ.XhZPypxjhaeJbdJzNozOKmKPbFqM9CWkAil8WiXFaAE"></iframe></figure><h2 id="generating-timestamp-ranges-on-postgres">Generating timestamp ranges on Postgres</h2><p>The <code>generate_series</code> on Postgres can produce results with other types different than integers, while ClickHouse®’s <code>range</code> and <code>numbers</code> only output integers. But, with some smart logic, we can achieve the same results. For example, on Postgres you’d generate a time-series with a DateTime value for each hour in a day this way, as in described <a href="https://hakibenita.com/sql-for-data-analysis#generating-data">here</a>:</p><figure class="kg-card kg-embed-card"><iframe loading="lazy" width="100%" src="https://snippets.tinybird.co/endpoint?code=WITH%20daterange%20AS%20%28%0A%20%20%20%20SELECT%20%2A%0A%20%20%20%20FROM%20generate_series%28%0A%20%20%20%20%20%20%20%20%272021-01-01%20UTC%27%3A%3Atimestamptz%2C%20--%20start%0A%20%20%20%20%20%20%20%20%272021-01-02%20UTC%27%3A%3Atimestamptz%2C%20--%20stop%0A%20%20%20%20%20%20%20%20interval%20%271%20hour%27%20%20%20--%20step%0A%20%20%20%20%29%20AS%20t%28hh%29%0A%29%20SELECT%20%2A%20FROM%20daterange%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20hh%0A%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%0A%202021-01-01%2000%3A00%3A00%2B00%0A%202021-01-01%2001%3A00%3A00%2B00%0A%202021-01-01%2002%3A00%3A00%2B00%0A%20...%0A%202021-01-01%2022%3A00%3A00%2B00%0A%202021-01-01%2023%3A00%3A00%2B00%0A%202021-01-02%2000%3A00%3A00%2B00%0A%20&amp;language=Tinybird&amp;title=The%20generate_series%20function%20of%20Postgres&amp;run=&amp;token="></iframe></figure><h3 id="generate-a-datetime-time-series-on-clickhouse-specifying-the-start-and-end-datetimes-and-the-step">Generate a DateTime time series on ClickHouse®, specifying the start and end DateTimes, and the step</h3><p>On ClickHouse®, you can achieve the same this way:</p><figure class="kg-card kg-embed-card"><iframe loading="lazy" width="100%" src="https://snippets.tinybird.co/endpoint?code=WITH%20%0A%20%20%20%20toStartOfDay%28toDate%28%272021-01-01%27%29%29%20AS%20start%2C%0A%20%20%20%20toStartOfDay%28toDate%28%272021-01-02%27%29%29%20AS%20end%0ASELECT%20arrayJoin%28arrayMap%28x%20-%3E%20toDateTime%28x%29%2C%20range%28toUInt32%28start%29%2C%20toUInt32%28end%29%2C%203600%29%29%29%20as%20hh%0A&amp;language=Tinybird&amp;title=Time%20series%20on%20ClickHouse%20given%20the%20start%20and%20end%20date%20and%20the%20step%20size%20&amp;run=run&amp;token=p.eyJ1IjogIjdmOTIwMmMzLWM1ZjctNDU4Ni1hZDUxLTdmYzUzNTRlMTk5YSIsICJpZCI6ICI3N2NiMDljOS1hYjVjLTQ2MzYtYTA4Yi00ZDYwNDQwMzUyZTYifQ.XhZPypxjhaeJbdJzNozOKmKPbFqM9CWkAil8WiXFaAE"></iframe></figure><h2 id="generate-a-datetime-time-series-specifying-the-start-date-and-the-number-of-intervals">Generate a DateTime time series specifying the start date and the number of intervals</h2><p>Another way of doing the same thing:</p><figure class="kg-card kg-embed-card"><iframe loading="lazy" width="100%" src="https://snippets.tinybird.co/endpoint?code=WITH%20toDate%28%272021-01-01%27%29%20as%20start%0ASELECT%20addHours%28toDate%28start%29%2C%20number%29%20AS%20hh%0AFROM%20%28%0A%20%20%20%20SELECT%20arrayJoin%28range%280%2C%2024%29%29%20AS%20number%0A%29%0A&amp;language=Tinybird&amp;title=Time%20series%20on%20ClickHouse%20given%20start%20date%2C%20number%20of%20intervals%20and%20interval%20size&amp;run=run&amp;token=p.eyJ1IjogIjdmOTIwMmMzLWM1ZjctNDU4Ni1hZDUxLTdmYzUzNTRlMTk5YSIsICJpZCI6ICI3N2NiMDljOS1hYjVjLTQ2MzYtYTA4Yi00ZDYwNDQwMzUyZTYifQ.XhZPypxjhaeJbdJzNozOKmKPbFqM9CWkAil8WiXFaAE"></iframe></figure><p>More functions like <code>addHours</code> are available: <a href="https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#date_add"><code>dateAdd</code></a>, <a href="https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#timestamp_add"><code>timestampAdd</code></a> and <a href="https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#addyears-addmonths-addweeks-adddays-addhours-addminutes-addseconds-addquarters">addYears, addMonths, addWeeks, addDays, addHours, addMinutes, addSeconds, addQuarters</a>.</p><h3 id="generate-a-time-series-using-timeslots">Generate a time series using timeSlots</h3><p>Using the <a href="https://clickhouse.tech/docs/en/sql-reference/functions/date-time-functions/#timeslotsstarttime-duration-size"><code>timeSlots</code></a> function, we can specify the start (DateTime), duration (seconds) and step (seconds) and it generates an array of DateTime values.</p><figure class="kg-card kg-embed-card"><iframe loading="lazy" width="100%" src="https://snippets.tinybird.co/endpoint?code=WITH%20toDateTime%28%272021-01-01%2000%3A00%3A00%27%29%20AS%20start%0ASELECT%20arrayJoin%28timeSlots%28start%2C%20toUInt32%2824%20%2A%203600%29%2C%203600%29%29%20AS%20hh%0A&amp;language=Tinybird&amp;title=Time%20series%20on%20ClickHouse%20using%20the%20timeSlots%20function&amp;run=run&amp;token=p.eyJ1IjogIjdmOTIwMmMzLWM1ZjctNDU4Ni1hZDUxLTdmYzUzNTRlMTk5YSIsICJpZCI6ICI3N2NiMDljOS1hYjVjLTQ2MzYtYTA4Yi00ZDYwNDQwMzUyZTYifQ.XhZPypxjhaeJbdJzNozOKmKPbFqM9CWkAil8WiXFaAE"></iframe></figure><h3 id="generate-a-date-time-series-specifying-the-start-and-end-date-and-the-step">Generate a Date time series specifying the start and end date and the step</h3><p>If you want to generate Date instead of DateTime objects, you’d change the <code>toDateTime</code> function by <code>toDate</code> from the first snippet. This is how you’d generate all the dates of January:</p><figure class="kg-card kg-embed-card"><iframe loading="lazy" width="100%" src="https://snippets.tinybird.co/endpoint?code=WITH%0A%20%20%20%20toStartOfDay%28toDate%28%272021-01-01%27%29%29%20AS%20start%2C%0A%20%20%20%20toStartOfDay%28toDate%28%272021-02-01%27%29%29%20AS%20end%0ASELECT%20arrayJoin%28arrayMap%28x%20-%3E%20toDate%28x%29%2C%20range%28toUInt32%28start%29%2C%20toUInt32%28end%29%2C%2024%20%2A%203600%29%29%29%20as%20hh%0A&amp;language=Tinybird&amp;title=Time%20series%20on%20ClickHouse%20given%20the%20start%20and%20end%20date%20and%20the%20step%20size%20&amp;run=run&amp;token=p.eyJ1IjogIjdmOTIwMmMzLWM1ZjctNDU4Ni1hZDUxLTdmYzUzNTRlMTk5YSIsICJpZCI6ICI3N2NiMDljOS1hYjVjLTQ2MzYtYTA4Yi00ZDYwNDQwMzUyZTYifQ.XhZPypxjhaeJbdJzNozOKmKPbFqM9CWkAil8WiXFaAE"></iframe></figure>
