> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mindsdb.com/llms.txt
> Use this file to discover all available pages before exploring further.

# JOBS

MindsDB enables you to automate any pipeline using JOBS, which grant you the power to schedule any query at any frequency. Additionally, it introduces the keyword <strong>[LAST](#last)</strong>, offering the capability for a JOB to act solely on new data, essentially treating any data source as a stream.

<p align="center">
  <img src="https://docs.google.com/drawings/d/e/2PACX-1vT_q7R0X4HHsSxHaMPJ2RgFtF-RP_sK6gjC9Kz4cG99AHi94yDh2dPttax7Za54IU5me4Zs4JwmW_of/pub?w=955&h=456" />
</p>

## Description

The `CREATE JOB` statement lets you schedule the execution of queries by providing relevant parameters, such as start date, end date, or repetition frequency.

## Syntax

### `CREATE JOB`

Here is the syntax:

```sql theme={null}
CREATE JOB [IF NOT EXISTS] [project_name.]job_name [AS] (
   <statement_1>[; <statement_2>][; ...]
)
[START <date>]
[END <date>]
[EVERY [number] <period>]
[IF (<statement_1>[; <statement_2>][; ...])];
```

Where:

| Expression                                     | Description                                                                                                                                                                                    |
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `[project_name.]job_name`                      | Name of the job preceded by an optional project name where the job is to be created. If you do not provide the `project_name` value, then the job is created in the default `mindsdb` project. |
| `<statement_1>[; <statement_2>][; ...]`        | One or more statements separated by `;` to be executed by the job.                                                                                                                             |
| `[START <date>]`                               | Optional. The date when the job starts its periodical or one-time execution. If not set, it is the current system date.                                                                        |
| `[END <date>]`                                 | Optional. The date when the job ends its periodical or one-time execution. If it is not set (and the repetition rules are set), then the job repeats forever.                                  |
| `[EVERY [number] <period>]`                    | Optional. The repetition rules for the job. If not set, the job runs once, not considering the end date value. If the `number` value is not set, it defaults to 1.                             |
| `[IF (<statement_1>[; <statement_2>][; ...])]` | Optional. If the last statement returns one or more rows, only then the job will execute.                                                                                                      |

<Info>
  **Available `<date>` formats**

  Here are the supported `<date>` formats:

  * `'%Y-%m-%d %H:%M:%S'`
  * `'%Y-%m-%d'`

  Please note that the default time zone is UTC.
</Info>

<Info>
  **Available `<period>` values**

  And the supported `<period>` values:

  * `minute` / `minutes` / `min`
  * `hour` / `hours`
  * `day` / `days`
  * `week` / `weeks`
  * `month` / `months`
</Info>

Further, you can query all jobs and their execution history like this:

```sql theme={null}
SHOW JOBS;
SELECT * FROM [project_name.]jobs WHERE name = 'job_name';
SELECT * FROM log.jobs_history WHERE project = 'mindsdb' AND name = 'job_name';
```

### `LAST`

MindsDB provides a custom `LAST` keyword that enables you to fetch data inserted after the last time you queried for it. It is a convenient way to select only the newly added data rows when running a job.

Imagine you have the `fruit_data` table that contains the following:

```sql theme={null}
+-------+-----------+
| id    | name      |
+-------+-----------+
| 1     | apple     |
| 2     | orange    |
+-------+-----------+
```

When you run the `SELECT` query with the `LAST` keyword for the first time, it'll give an empty output.

```sql theme={null}
SELECT id, name
FROM fruit_data
WHERE id > LAST;
```

This query returns:

```sql theme={null}
+-------+-----------+
| id    | name      |
+-------+-----------+
| null  | null      |
+-------+-----------+
```

<Tip>
  If you want to specify a concrete value for `LAST` in the first execution of such a query, use the `COALESCE(LAST, <value>)` function.

  ```sql theme={null}
  SELECT id, name
  FROM fruit_data
  WHERE id > COALESCE(LAST, 1);
  ```

  It will result in executing the following query in the first run:

  ```sql theme={null}
  SELECT id, name
  FROM fruit_data
  WHERE id > 1;
  ```

  And the below query at each subsequent run:

  ```sql theme={null}
  SELECT id, name
  FROM fruit_data
  WHERE id > LAST;
  ```
</Tip>

Now imagine you inserted a new record into the `fruit_data` table:

```sql theme={null}
+-------+-----------+
| id    | name      |
+-------+-----------+
| 1     | apple     |
| 2     | orange    |
| 3     | pear      |
+-------+-----------+
```

When you run the `SELECT` query with the `LAST` keyword again, you'll get only the newly added record as output.

```sql theme={null}
SELECT id, name
FROM fruit_data
WHERE id > LAST;
```

This query returns:

```sql theme={null}
+-------+-----------+
| id    | name      |
+-------+-----------+
| 3     | pear      |
+-------+-----------+
```

From this point on, whenever you add new records into the `fruit_data` table, it'll be returned by the next run of the `SELECT` query with the `LAST` keyword. And, if you do not add any new records between the query runs, then the output will be null.

If you want to clear context for the `LAST` keyword in the editor, then run `set context = 0` or `set context = null`.

### Conditional Jobs

Here is how you can create a conditional job that will execute periodically only if there is new data available:

```sql theme={null}
CREATE JOB conditional_job (

    FINETUNE MODEL model_name
    FROM (     
        SELECT *
        FROM datasource.table_name
        WHERE incremental_column > LAST
    )
)
EVERY 1 min
IF (
    SELECT *
    FROM datasource.table_name
    WHERE incremental_column > LAST
);
```

The above job will be triggered every minute, but it will execute its task (i.e. finetuning the model) only if there is new data available.

## Examples

### Example 1: Retrain a Model

In this example, we create a job in the current project to retrain the `home_rentals_model` model and insert predictions into the `rentals` table.

```sql theme={null}
CREATE JOB retrain_model_and_save_predictions (

   RETRAIN mindsdb.home_rentals_model
   USING
      join_learn_process = true;

   INSERT INTO my_integration.rentals (
      SELECT m.rental_price, m.rental_price_explain
      FROM mindsdb.home_rentals_model AS m
      JOIN example_db.demo_data.home_rentals AS d
   )
)
END '2023-04-01 00:00:00'
EVERY 2 days;
```

<Tip>
  Please note that the `join_learn_process` parameter in the `USING` clause of the [`RETRAIN`](/sql/api/retrain) statement ensures that the retraining process completes before inserting predictions into a table. In general, this parameter is used to prevent several retrain processes from running simultaneously.
</Tip>

The `retrain_model_and_save_predictions` job starts its execution on the current system date and ends on the 1st of April 2023. The job is executed every 2 days.

### Example 2: Save Predictions

In this example, the job creates a table named as `result_{{START_DATETIME}}` and inserts predictions into it.

```sql theme={null}
CREATE JOB save_predictions (

   CREATE TABLE my_integration.`result_{{START_DATETIME}}` (
      SELECT m.rental_price, m.rental_price_explain
      FROM mindsdb.home_rentals_model AS m
      JOIN example_db.demo_data.home_rentals AS d
   )
)
EVERY hour;
```

<Tip>
  Please note that the uniqueness of the created table name is ensured here by using the `{{START_DATETIME}}` variable that is replaced at runtime by the date and time of the current run.

  You can use the following variables for this purpose:

  * `PREVIOUS_START_DATETIME` is replaced by date and time of the previous run of this job.
  * `START_DATETIME` is replaced by date and time of the current job run.
  * `START_DATE` is replaced by date of the current job run.
</Tip>

The `save_predictions` job starts its execution on the current system date and repeats every 2 hours until it is manually disabled.

### Example 3: Drop a Model

In this example, we create a job to drop the `home_rentals_model` model scheduled on the 1st of April 2023.

```sql theme={null}
CREATE JOB drop_model (

   DROP MODEL mindsdb.home_rentals_model
) 
START '2023-04-01';
```

This job runs once on the 1st of April 2023.

### Example 4: Twitter Chatbot

You can easily create a chatbot to respond to tweets using jobs. But before you get to it, you should connect your Twitter account to MindsDB following the instructions [here](/integrations/app-integrations/twitter).

<Tip>
  Follow the [tutorial on how to create a Twitter chatbot](/sql/tutorials/twitter-chatbot) to learn the details.
</Tip>

Let's create a job that runs every hour, checks for new tweets, and responds using the OpenAI model.

```sql theme={null}
CREATE JOB mindsdb.gpt4_twitter_job AS (

   -- insert into tweets the output of joining model and new tweets
   INSERT INTO my_twitter_v2.tweets (in_reply_to_tweet_id, text)
      SELECT
         t.id AS in_reply_to_tweet_id,
         r.response AS text
      FROM my_twitter.tweets t
      JOIN mindsdb.snoopstein_model r
         WHERE
            t.query = '(@snoopstein OR @snoop_stein OR #snoopstein OR #snoop_stein) -is:retweet -from:snoop_stein'
         AND t.created_at > LAST
      LIMIT 10
)
EVERY hour;
```

The [`SELECT`](/sql/api/select) statement joins the data table with the model table to get responses for newly posted tweets, thanks to the `LAST` keyword. Then, the [`INSERT INTO`](/sql/api/insert) statement writes these responses to the `tweets` table of the `my_twitter` integration.

<Tip>
  To learn more about OpenAI integration with MindsDB, visit our docs [here](/nlp/nlp-mindsdb-openai).
</Tip>

## Additional Configuration

Here is the template of the `config.json` file that you can pass as a parameter when starting your local MindsDB instance:

```bash theme={null}
"jobs": {
        "disable": true,
        "check_interval": 30
      }
```

The `disable` parameter defines whether the scheduler is active (`true`) or not (`false`). By default, in the MindsDB Editor, the scheduler is active.

The `check_interval` parameter defines the interval in seconds between consecutive checks of the scheduler table. By default, in the MindsDB Editor, it is 30 seconds.

You can modify the default configuration in your local MindsDB installation by creating a `config.json` file and starting MindsDB with this file as a parameter. You can find detailed instructions [here](/setup/custom-config#starting-mindsdb-with-extended-configuration).
