
These four pages:

- [table t1](./table-t1/)
- [table t2](./table-t2/)
- [table t3](./table-t3/)
- [table t4](./table-t4/)

contain scripts to create and populate tables with data sets that are useful for demonstrating window function semantics.

Each table uses a surrogate `uuid` primary key whose values are provided by the function `gen_random_uuid()`, brought by the `pgcrypto` extension. The procedure to populate table _"t4"_ also uses the function `normal_rand()`, brought by the `tablefunc` extension. These extensions are described in the sections [pgcrypto](../../../../../../additional-features/pg-extensions/extension-pgcrypto) and [tablefunc](../../../../../../additional-features/pg-extensions/extension-tablefunc). Each is a pre-bundled extension. This means that the installation for each will work without any preparatory steps, as long as you install them as a `superuser` like this:

```plpgsql
create extension pgcrypto;
create extension tablefunc;
```

If you plan to run the code samples in this main "_Window functions"_ section on your laptop using a YugabyteDB cluster that you've created for your own personal use, then you probably have already adopted the habit of running any and all _ad hoc_ tests as a `superuser`. If so, then simply install the [pgcrypto](../../../../../../additional-features/pg-extensions/extension-pgcrypto) and [tablefunc](../../../../../../additional-features/pg-extensions/extension-tablefunc) extensions just as you'd do anything else and then create the tables _"t1"_, _"t2"_, _"t3"_, and _"t4"_.

{{< note title="Note 1: about the installation of extensions" >}}

If you've established the practice of creating different databases within your cluster for different purposes, and within a database using a regime of different users that own different schemas to model how a real-world application would be organized, then you'll doubtless want to create and install the extensions in a dedicated central schema and ensure that this is in the _search path_ for all ordinary users.

{{< /note >}}

{{< note title="Note 2: about the use of the gen_random_uuid() function" >}}

Yugabyte recommends that, when you want a self-populating surrogate primary key column, you should use the approach shown here for the test tables, like this:

```sql
create table my_table(
  k uuid default gen_random_uuid() primary key, ...
```

This is preferred to using, for example `serial` or `bigserial`, like this:

```sql
create table t4(
  k serial primary key, ...
```

(This approach that is common, and that works well, in PostgreSQL—a monolithic SQL database.) This is because `serial` and `bigserial` use a `SEQUENCE`  to generate unique values, and this involves expensive coordination between the nodes in a YugabyteDB cluster. In contrast, any invocation of `gen_random_uuid()` on any node, will reliably produce a new globally unique value entirely algorithmically. This brings a noticeable performance benefit.

The tables _"t1"_, _"t2"_, and _"t3"_ have only a handful of rows and so this performance benefit is well below the noise level. But [table _"t4"_](./table-t4/) is populated using a purpose-written procedure parameterized with the number of rows to create. You get the most convincing demonstration effect with a large number, like _100,000_, rows.

You can expect to see that populating the table "t4" if you use `gen_random_uuid()` is about _20x_ faster than if you use a sequence.

{{< /note >}}

Each of the tables _"t1"_, _"t2"_, _"t3"_, and _"t4"_ is populated so that the values of interest for the demonstrations come back in random order (as you are taught to expect) when a query has no `ORDER BY` clause. This takes just a little programming effort for the tables _"t1"_, _"t2"_, and _"t3"_. Effort is needed because, following a bulk insert into a newly-created table, queries with no `ORDER BY` clause tend to see the rows come back in the order in which they are inserted. And the `INSERT` statements for the tables _"t1"_, _"t2"_, and _"t3"_ explicitly list the to-be-inserted values in an intuitive order where they increase monotonically. No effort is needed for table _"t4"_ because the values of interest are generated by `normal_rand()`—which generates its values in a random order.

Deliberately subverting this tendency (that when rows are inserted naïvely, as they usually are for functionality demonstrations, they come back in a "natural" order, even with no `ORDER BY`) allows a vivid demonstration of the fact that if the [`window_definition`](../../../../syntax_resources/grammar_diagrams/#window-definition) that's used to invoke _any_ window function has no window`ORDER BY` clause (even if there is such a clause at overall query level), then the results are unpredictable and therefore meaningless. This is demonstrated in the section [Showing the importance of the window ORDER BY clause](../../functionality-overview/#showing-the-importance-of-the-window-order-by-clause). (There are cases where the order doesn't matter—for example, when the set of rows is the input to a conventionally invoked aggregate function.)

{{< note title="Save a script to (re)create all four test tables." >}}

It's a good idea to save a script that you can use quickly and effortlessly to create the test tables should you lose, or change, them. This can happen easily with a YugabyteDB cluster on your laptop that you use for all sorts of _ad hoc_ tests. For example, it takes only moments to destroy and re-create the cluster (or even to upgrade to a new version of YugabyteDB)—and this is common practice for certain kinds of test.

 Of course, you must first visit each of these pages:

- [table t1](./table-t1/)
- [table t2](./table-t2/)
- [table t3](./table-t3/)
- [table t4](./table-t4/)

and save each of the scripts that these present onto the same directory where you save the  "Master" installation script.

Save this script as, for example, `install_all_tables.sql`:

```plpgsql
-- You can run this script time and again. It will always finish silently.

\i t1.sql
\echo 't1 done'

\i t2.sql
\echo 't2 done'

\i t3.sql
\echo 't3 done'

\i t4_1.sql
\i t4_2.sql
\echo 't4 done'
```

Then you can simply do this whenever you need to re-establish the state that the code examples rely on:

```plpgsql
\i install_all_tables.sql
```

It takes only a few seconds to finish. Each of the scripts `t1.sql`, `t2.sql`, `t3.sql`, `t4_1.sql`, and `t4_2.sql` that it runs is designed to be able to be repeated. Each finishes silently on its first and all subsequent runs.

{{< /note >}}
