# SQL Database quickstart

This guide instructs you through storing and reading your first row in [SQL Database](/en/documentation/platform/sql-database/). By the end you will have:

- Your first database, with the status `created`.
- A `users` table inside it.
- One row stored in that table.
- The same row returned by a `SELECT` statement.

The result rests on two objects. The **database** is the container, and its name cannot be changed after creation. Each **table** lives inside one database, and this guide creates the table with a `CREATE TABLE` statement. A database is provisioned asynchronously. Its status reads `creating` first, and a statement runs against it only after the status reads `created`.

---

Select the interface you will use. The prerequisites and every stage below follow that choice.

## Prerequisites

- SQL Database enabled on the account. The product is in Preview, and access is requested through the technical support team. To request it, refer to [Technical Support](/en/documentation/support/).
- The **Edit SQL Database** permission on the account. It grants permission to create and edit databases and their data. For more information, refer to [Teams Permissions](/en/documentation/fundamentals/teams-permissions/).

**Console**

- Access to Azion Console. To sign in, refer to [How to access Azion Console](/en/documentation/guides/platform/account-and-billing/how-to-access-azion-console/).

**API**

- A [personal token](/en/documentation/guides/platform/account-and-billing/personal-tokens/) and `curl`.

---

## Create a database

A database holds the tables you create. Its name is 6 to 50 characters, and uses letters, numbers, and the hyphen. Provisioning is asynchronous, so the database is not queryable the moment it is created.

**Console**

To create the database in Azion Console:

1. **Open the database list**

   Access [Azion Console](https://console.azion.com/) > **SQL Database**.

2. **Open the create form**

   Start a new database from the list, with the **SQL Database** control.

3. **Name the database**

   Under **General**, in **Name**, enter a name of your own. A name another database in the account holds is refused.

4. **Select Save**

The database appears in the list, which shows its **Name**, **Status**, **Last Editor**, and **Last Modified**. Its status reads `creating` until it reads `created`, which takes about 15 seconds.

**API**

To create the database with the Azion API and wait for it to be ready:

1. **Send the create request**

   Replace `[TOKEN VALUE]` with your personal token, and `my-database` with a name of your own:

   ```bash
   curl --request POST \
     --url https://api.azion.com/v4/workspace/sql/databases \
     --header 'Accept: application/json' \
     --header 'Authorization: Token [TOKEN VALUE]' \
     --header 'Content-Type: application/json' \
     --data '{
     "name": "my-database"
   }'
   ```

2. **Read the response**

   A `202` carries the database:

   ```json
   {
     "state": "pending",
     "data": {
       "id": 1235,
       "name": "my-database",
       "status": "creating",
       "active": true,
       "last_modified": "2026-01-01T12:13:01.399970Z",
       "last_editor": "user@example.com",
       "product_version": "1.0"
     }
   }
   ```

   Record the `id`, `1235` in this sample. Every request below addresses the database by it. A `400` with the code `14001` means the account already holds a database with that name. Choose a different name and send the request again.

3. **Poll until the status reads created**

   Replace `1235` with the `id` the create response returned:

   ```bash
   curl --request GET \
     --url https://api.azion.com/v4/workspace/sql/databases/1235 \
     --header 'Accept: application/json' \
     --header 'Authorization: Token [TOKEN VALUE]'
   ```

   A `200` carries the database, and this response has no `state` key:

   ```json
   {
     "data": {
       "id": 1235,
       "name": "my-database",
       "status": "created",
       "active": true,
       "last_modified": "2026-01-01T12:13:13.920246Z",
       "last_editor": "user@example.com",
       "product_version": "1.0"
     }
   }
   ```

   Provisioning takes about 15 seconds. Send the request again while the status reads `creating`.

The database is ready when `status` reads `created`. Do not skip the wait: a statement sent while the status reads `creating` cannot succeed.

---

## Create a table

A table holds the rows you store, and its columns are fixed by the `CREATE TABLE` statement.

**Console**

The **Editor** tab runs SQL against one database. To create the table this guide uses:

1. **Open the database**

   In the **SQL Database** list, select the database you created.

2. **Go to the Editor tab**

3. **Enter the CREATE TABLE statement**

   Create the `users` table with three columns:

   ```sql
   CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT);
   ```

4. **Select Run query**

The table appears under the **Tables** tab.

**API**

The query endpoint runs SQL against one database. The body carries a `statements` array, and Azion runs the statements in order.

1. **Send the query request**

   Replace `1235` with the `id` of your database:

   ```bash
   curl --request POST \
     --url https://api.azion.com/v4/workspace/sql/databases/1235/query \
     --header 'Accept: application/json' \
     --header 'Authorization: Token [TOKEN VALUE]' \
     --header 'Content-Type: application/json' \
     --data '{
     "statements": ["CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT);"]
   }'
   ```

2. **Read the response**

   A `200` carries one entry per statement:

   ```json
   {
     "state": "executed",
     "data": [
       {
         "results": {
           "columns": [],
           "rows": [],
           "rows_read": 1,
           "rows_written": 2,
           "query_duration_ms": 2.592
         }
       }
     ]
   }
   ```

   The statement returns no rows, so `columns` and `rows` are empty. It still reports rows read and written, because `CREATE TABLE` writes the schema itself. Azion bills on `rows_read` and `rows_written`, and returns both per statement.

The database holds a `users` table with no rows.

---

## Insert a row

An `INSERT` statement stores a row in the table.

**Console**

To store the first row from the **Editor** tab:

1. **Enter the INSERT statement**

   In the **Editor** tab, enter the following statement:

   ```sql
   INSERT INTO users (name, email) VALUES ('Ada', 'ada@example.com');
   ```

2. **Select Run query**

The table holds one row.

**API**

To store the first row through the query endpoint:

1. **Send the query request**

   The `INSERT` statement carries single quotes, so the body is sent on standard input:

   ```bash
   curl --request POST \
     --url https://api.azion.com/v4/workspace/sql/databases/1235/query \
     --header 'Accept: application/json' \
     --header 'Authorization: Token [TOKEN VALUE]' \
     --header 'Content-Type: application/json' \
     --data @- <<'EOF'
   {
     "statements": ["INSERT INTO users (name, email) VALUES ('Ada', 'ada@example.com');"]
   }
   EOF
   ```

2. **Read the response**

   A `200` reports the write:

   ```json
   {
     "state": "executed",
     "data": [
       {
         "results": {
           "columns": [],
           "rows": [],
           "rows_read": 0,
           "rows_written": 1,
           "query_duration_ms": 2.649
         }
       }
     ]
   }
   ```

The table holds one row.

---

## Read the row back

A `SELECT` statement returns what the table holds.

**Console**

To read the row you inserted from the **Editor** tab:

1. **Enter the SELECT statement**

   In the **Editor** tab, enter the following statement:

   ```sql
   SELECT id, name, email FROM users;
   ```

2. **Select Run query**

The result carries one row under the columns `id`, `name`, and `email`: `1`, `Ada`, and `ada@example.com`.

**API**

To read the row you inserted through the query endpoint:

1. **Send the query request**

   ```bash
   curl --request POST \
     --url https://api.azion.com/v4/workspace/sql/databases/1235/query \
     --header 'Accept: application/json' \
     --header 'Authorization: Token [TOKEN VALUE]' \
     --header 'Content-Type: application/json' \
     --data '{
     "statements": ["SELECT id, name, email FROM users;"]
   }'
   ```

2. **Read the response**

   A `200` carries the column names and one array per row:

   ```json
   {
     "state": "executed",
     "data": [
       {
         "results": {
           "columns": ["id", "name", "email"],
           "rows": [[1, "Ada", "ada@example.com"]],
           "rows_read": 1,
           "rows_written": 0,
           "query_duration_ms": 0.041
         }
       }
     ]
   }
   ```

The result carries one row under the columns `id`, `name`, and `email`: `1`, `Ada`, and `ada@example.com`.

Your first database holds a `users` table with one row, and reads it back. The same statements run in Azion Console, through the Azion API, and inside a function.

> **Caution**
>
> A statement that fails does not fail the API request. The response answers HTTP `200`, and the entry for that statement carries `error` in place of `results`:
>
> ```json
> {
>   "state": "executed",
>   "data": [
>     {
>       "error": "no such table: nope"
>     }
>   ]
> }
> ```
>
> Check `data[].error` on every statement, not the HTTP status code. For more information, refer to [Databases and queries](/en/documentation/platform/sql-database/databases-and-queries/).

---

## Next steps

- [How SQL Database works](/en/documentation/platform/sql-database/how-it-works.md): The main instance, the read replicas, and how a statement reaches your data.
- [Databases and queries](/en/documentation/platform/sql-database/databases-and-queries.md): Every field a database carries, the five operations, and the error codes.
- [Query a database from a function](/en/documentation/guides/application-development/data/retrieve-data-with-functions.md): Read the same table from a function at run time.
- [SQL Database limits](/en/documentation/platform/sql-database/limits.md): The bounds on a name and a table, and the usage included in each plan.
