> For the complete documentation index, see [llms.txt](https://navixy.com/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://navixy.com/docs/analytics/ru/example-queries/leasing.md).

# Лизинг

Шаблоны SQL-запросов для банковской и лизинговой аналитики, включая жизненный цикл активов, соответствие договорам, планирование техобслуживания и мониторинг лимитов использования

{% hint style="warning" %}
Включить **IoT Query** перед использованием данных для построения комплексной аналитики. Если у вас его еще нет, свяжитесь с нами для получения подробностей активации - <iotquery@navixy.com>
{% endhint %}

Лизинговые компании (в частности банки и провайдеры лизинга автопарка) сохраняют право собственности на транспортное средство или оборудование, в то время как клиент лишь арендует его использование, поэтому они несут риск, связанный с Активом, на протяжении всего контракта. 

Чтобы защитить остаточную стоимость, соблюдать договорные ограничения (Пробег, географию, Техобслуживание) и упростить обязательства по полному сервису, они полагаются на Navixy.  Данные GPS в реальном времени, диагностика на основе датчиков и поведенческая аналитика позволяют им проверять условия использования, автоматизировать Планирование Техобслуживания, заранее выявлять механические неисправности, рассчитывать штрафы или сборы за превышение пробега и, при необходимости, обездвиживать или возвращать Актив — все это защищает их инвестиции, снижает операционные затраты и повышает прозрачность для клиентов на протяжении всего жизненного цикла лизинга.

Navixy **IoT Query** поможет организовать любой вид аналитики на каждом этапе лизингового контракта. Лизинговый контракт проходит через несколько предсказуемых фаз: Онбординг и настройка Актива → Операционная фаза → Контроль рисков и соответствия

Следующие SQL-рецепты в вашей книге в совокупности отслеживают все критические этапы этого жизненного цикла:

| Этап жизненного цикла                              | Цели и контрольные точки                                                                                                                                        | Покрываемые сценарии использования / рецепты                                                                                                                                                                                              |
| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Онбординг  & настройка Актив                       | • Зарегистрировать транспортное средство, активировать Страховку и учетные данные Водителя. • Импортировать Активы в клиентский портал с правильной видимостью. | Оповещения об истечении регистрации/Страховки – базовые даты зафиксированы. Истечение срока водительского удостоверения – проверяет Водители перед выпуском.                                                                              |
| Планирование профилактического Техобслуживания     | • Устанавливайте повторяющиеся графики обслуживания, основанные на пробеге и времени. • Гарантируйте сезонную замену шин.                                       | Регулярные проверки по интервалу – задания, привязанные к календарю. Обслуживание по порогу пробега – правила малого/большого обслуживания, привязанные к км. Мониторинг моточасов двигателя – обслуживание техники, привязанное к часам. |
| Ограничения использования, привязанные к контракту | • Контролируйте лимиты пробега и финансовые ограничения. • Выявляйте чрезмерное использование заранее, чтобы избежать сюрпризов к концу срока.                  | Лимит пробега и штрафы – контроль годового / общего по контракту пробега.                                                                                                                                                                 |
| Поведение водителя и актива в реальном времени     | • Защищайте ценность актива; обучайте водителей. • Выявляйте злоупотребления, которые лишают покрытия «full-service».                                           | Резкое торможение. Резкое ускорение. Резкие повороты/прохождение поворотов.                                                                                                                                                               |
| Контроль рисков и соблюдения требований            | • Держите активы в пределах географических и договорных границ. • Сохраняйте право отключать или возвращать.                                                    | Выход из геозоны (граница страны) – мгновенное оповещение о нарушении границ территории. Зажигание и определение простоя – мониторинг перерасхода топлива / нецелевого использования.                                                     |

### Шаблон панели мониторинга

Хотя приведенные ниже SQL-рецепты обеспечивают полный контроль над аналитикой лизинга, вы можете начать быстрее с готовой панели мониторинга, которая визуализирует критически важные метрики на протяжении всего жизненного цикла лизинга. Шаблон избавляет от необходимости создавать запросы и визуализации с нуля. Импортируйте его, настройте параметры и сразу начните мониторинг соответствия, рисков и защиты активов.

Шаблон охватывает ключевые рабочие процессы лизинга: мониторинг истечения регистрации и страховки, мониторинг срока действия водительского удостоверения, обнаружение торможения и ускорения с классификацией по степени серьезности, анализ времени простоя и мониторинг активности устройства.

<figure><img src="https://1999959041-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoFNFEIINiGFbhi3Px3dE%2Fuploads%2Fgit-blob-64ef38d2255e595e6b5ee405e94ff208302d8131%2Fimage%20(16).png?alt=media" alt=""><figcaption></figcaption></figure>

Импортируйте конфигурацию в [Dashboard Studio](https://marketplace.navixy.com/shop/dashboard-studio/), настройте пороги для ваших контрактов (лимиты пробега, уровни серьезности поведения, параметры определения простоя) и разверните полное рабочее пространство для мониторинга. Это хорошо работает, когда командам нужны операционные панели мониторинга для ежедневного контроля соответствия и рисков без написания SQL.

**Предварительные требования:**

* IoT Query включен в вашей среде
* Dashboard Studio установлен и доступен
* По крайней мере 72 часа данных мониторинга
* Заполненные стандартные таблицы схемы: `Мониторинг_data_core`, `состояния`, `объекты`, `Транспорт`, `сотрудники`

**Конфигурация после импорта:**

После импорта шаблона адаптируйте его под ваши конкретные договоры лизинга и операционные пороговые значения:

1. Проверьте 72-часовой диапазон времени по умолчанию и при необходимости скорректируйте его, если доступность ваших данных отличается.
2. Задайте пороговые значения серьезности для событий вождения в параметрах запроса (по умолчанию: 60+ км/ч/с для предупреждений, 80+ км/ч/с для критических оповещений).
3. Настройте параметры определения холостого хода (по умолчанию: скорость ниже 5 км/ч, минимальная длительность 5 минут).
4. Обновите метки зоны геозоны в запросе о пересечении границы, если требуется мониторинг территориальных ограничений.
5. Используйте глобальный выбор времени, чтобы анализировать исторические периоды или сосредоточиться на недавней активности.

**JSON шаблона:**

{% file src="/files/187033a3ff9515ba78fb7485d070e773fba2f242" %}

{% code lineNumbers="true" expandable="true" %}

```json
{
  "id": null,
  "uid": "hello-world",
  "Теги": [
    "пример",
    "getting-started"
  ],
  "время": {
    "to": "now",
    "from": "now-72h"
  },
  "links": [],
  "style": "dark",
  "title": "Панель мониторинга лизинга",
  "panels": [
    {
      "id": 10,
      "type": "text",
      "title": "Зажигание & определение холостого хода",
      "gridPos": {
        "h": 4,
        "w": 24,
        "x": 0,
        "y": 158
      },
      "options": {
        "mode": "markdown",
        "content": " "
      },
      "x-navixy": {
        "sql": {
          "statement": ""
        },
        "dataset": {
          "shape": "table",
          "columns": {}
        }
      }
    },
    {
      "id": 11,
      "type": "piechart",
      "title": "Водители с ближайшими датами истечения срока действия",
      "gridPos": {
        "h": 12,
        "w": 12,
        "x": 12,
        "y": 0
      },
      "options": {
        "pieType": "donut"
      },
      "x-navixy": {
        "sql": {
          "params": {},
          "statement": "SELECT \r\n    CASE \r\n        WHEN (DATE(e.driver_license_valid_till) - CURRENT_DATE)::INTEGER < 0 THEN 'Expired'\r\n        ELSE 'Others'\r\n    END AS category,\r\n    COUNT(*) AS value\r\nFROM raw_business_data.employees e\r\nWHERE e.driver_license_valid_till IS NOT NULL\r\nGROUP BY category\r\nORDER BY category"
        },
        "verify": {
          "max_rows": 1000
        },
        "dataset": {
          "shape": "pie",
          "columns": {
            "value": {
              "type": "integer"
            },
            "category": {
              "type": "string"
            }
          }
        }
      }
    },
    {
      "id": 12,
      "type": "piechart",
      "title": "Транспорт с ближайшими сроками истечения", 
      "gridPos": {
        "h": 12,
        "w": 12,
        "x": 0,
        "y": 0
      },
      "options": {
        "pieType": "donut"
      },
      "x-navixy": {
        "sql": {
          "params": {},
          "statement": "WITH expiry_data AS (\r\n    SELECT \r\n        CASE \r\n            WHEN v.free_insurance_valid_till_date IS NOT NULL\r\n                AND (v.liability_insurance_valid_till IS NULL \r\n                      OR v.free_insurance_valid_till_date <= v.liability_insurance_valid_till)\r\n                THEN v.free_insurance_valid_till_date\r\n            WHEN v.liability_insurance_valid_till IS NOT NULL\r\n                THEN v.liability_insurance_valid_till\r\n            ELSE NULL\r\n        END AS nearest_expiry_date\r\n    FROM raw_business_data.vehicles v\r\n),\r\ncategorized_data AS (\r\n    SELECT \r\n        CASE \r\n            WHEN (DATE(nearest_expiry_date) - CURRENT_DATE)::INTEGER < 0 THEN 'Expired'\r\n            WHEN (DATE(nearest_expiry_date) - CURRENT_DATE)::INTEGER >= 0 \r\n                  AND (DATE(nearest_expiry_date) - CURRENT_DATE)::INTEGER < 30 THEN 'Expires within 30 days'\r\n            ELSE 'Others'\r\n        END AS category\r\n    FROM expiry_data\r\n    WHERE nearest_expiry_date IS NOT NULL\r\n)\r\nSELECT \r\n    category,\r\n    COUNT(*) AS value\r\nFROM categorized_data\r\nGROUP BY category\r\nORDER BY \r\n    CASE category\r\n        WHEN 'Expired' THEN 1\r\n        WHEN 'Expires within 30 days' THEN 2\r\n        WHEN 'Others' THEN 3\r\n    END"
        },
        "verify": {
          "max_rows": 1000
        },
        "dataset": {
          "shape": "pie",
          "columns": {
            "value": {
              "type": "integer"
            },
            "category": {
              "type": "string"
            }
          }
        }
      }
    },
    {
      "id": 13,
      "type": "barchart",
      "title": "События Торможения",
      "gridPos": {
        "h": 11,
        "w": 24,
        "x": 0,
        "y": 12
      },
      "options": {
        "textMode": "auto"
      },
      "x-navixy": {
        "sql": {
          "params": {},
          "statement": "WITH spd AS (\r\n          SELECT\r\n            device_id,\r\n            device_time,\r\n            speed/100.0 AS kmh,\r\n            LAG(speed/100.0) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_kmh,\r\n            EXTRACT(EPOCH FROM (device_time - LAG(device_time) OVER (PARTITION BY device_id ORDER BY device_time))) AS dt_sec\r\n          FROM\r\n            raw_telematics_data.tracking_data_core\r\n          WHERE 1=1\r\n        ),\r\n        decels AS (\r\n          SELECT\r\n            device_id,\r\n            device_time,\r\n            (prev_kmh - kmh) / NULLIF(dt_sec, 0) AS decel_kmh_per_sec\r\n          FROM\r\n            spd\r\n          WHERE\r\n            prev_kmh IS NOT NULL\r\n        ),\r\n        events_with_severity AS (\r\n          SELECT \r\n            DATE(d.device_time) AS category,\r\n            CASE \r\n              WHEN d.decel_kmh_per_sec >= 80 THEN 'Critical'\r\n              WHEN d.decel_kmh_per_sec >= 60 THEN 'Warning'\r\n              ELSE 'Normal'\r\n            END AS series\r\n          FROM decels d\r\n          WHERE d.decel_kmh_per_sec >= 60\r\n        )\r\n        SELECT \r\n          category,\r\n          COUNT(*) AS value,\r\n          series\r\n        FROM events_with_severity\r\n        GROUP BY category, series\r\n        ORDER BY series"
        },
        "verify": {
          "max_rows": 1000
        },
        "dataset": {
          "shape": "category_value",
          "columns": {
            "value": {
              "type": "integer"
            },
            "series": {
              "type": "string"
            },
            "category": {
              "type": "date"
            }
          }
        },
        "visualization": {
          "sortOrder": "none",
          "colorPalette": "vibrant"
        }
      }
    },
    {
      "id": 14,
      "type": "barchart",
      "title": "События Ускорение",
      "gridPos": {
        "h": 17,
        "w": 24,
        "x": 0,
        "y": 41
      },
      "options": {
        "orientation": "vertical"
      },
      "x-navixy": {
        "sql": {
          "params": {},
          "statement": "WITH spd AS (\r\n          SELECT\r\n            device_id,\r\n            device_time,\r\n            speed/100.0 AS kmh,\r\n            LAG(speed/100.0) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_kmh,\r\n            EXTRACT(EPOCH FROM (device_time - LAG(device_time) OVER (PARTITION BY device_id ORDER BY device_time))) AS dt_sec\r\n          FROM\r\n            raw_telematics_data.tracking_data_core\r\n        ),\r\n        accels AS (\r\n          SELECT\r\n            device_id,\r\n            device_time,\r\n            (kmh - prev_kmh) / NULLIF(dt_sec, 0) AS accel_kmh_per_sec\r\n          FROM\r\n            spd\r\n          WHERE\r\n            prev_kmh IS NOT NULL\r\n        ),\r\n        events_with_severity AS (\r\n          SELECT \r\n            DATE(a.device_time) AS category,\r\n            CASE \r\n              WHEN a.accel_kmh_per_sec >= 80 THEN 'Critical'\r\n              WHEN a.accel_kmh_per_sec >= 60 THEN 'Warning'\r\n              ELSE 'Normal'\r\n            END AS series\r\n          FROM accels a\r\n          WHERE a.accel_kmh_per_sec >= 60\r\n        )\r\n        SELECT \r\n          category,\r\n          COUNT(*) AS value,\r\n          series\r\n        FROM events_with_severity\r\n        GROUP BY category, series\r\n        ORDER BY series"
        },
        "verify": {
          "max_rows": 1000
        },
        "dataset": {
          "shape": "category_value",
          "columns": {
            "value": {
              "type": "integer"
            },
            "series": {
              "type": "string"
            },
            "category": {
              "type": "date"
            }
          }
        },
        "visualization": {
          "colorPalette": "vibrant"
        }
      }
    },
    {
      "id": 15,
      "type": "barchart",
      "title": "Резкие повороты / прохождение поворотов",
      "gridPos": {
        "h": 13,
        "w": 24,
        "x": 0,
        "y": 23
      },
      "options": {
        "orientation": "vertical"
      },
      "x-navixy": {
        "sql": {
          "params": {},
          "statement": "WITH pts AS (\r\n          SELECT\r\n            device_id,\r\n            device_time,\r\n            latitude/1e7::numeric AS lat,\r\n            longitude/1e7::numeric AS lon,\r\n            LAG(latitude/1e7::numeric) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_lat,\r\n            LAG(longitude/1e7::numeric) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_lon,\r\n            speed/100.0 AS kmh,\r\n            LAG(speed/100.0) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_kmh\r\n          FROM\r\n            raw_telematics_data.tracking_data_core\r\n        ),\r\n        bearing AS (\r\n          SELECT *,\r\n                 atan2(\r\n                   sin(radians(lon-prev_lon))*cos(radians(lat)),\r\n                   cos(radians(prev_lat))*sin(radians(lat)) -\r\n                   sin(radians(prev_lat))*cos(radians(lat))*cos(radians(lon-prev_lon))\r\n                 ) * 180/pi() AS heading_change\r\n          FROM pts\r\n          WHERE prev_lat IS NOT NULL AND prev_lon IS NOT NULL\r\n        ),\r\n        events_with_severity AS (\r\n          SELECT \r\n            DATE(b.device_time) AS category,\r\n            CASE \r\n              WHEN ABS(b.heading_change) >= 50 AND b.kmh >= 30 THEN 'Critical'\r\n              WHEN ABS(b.heading_change) >= 30 AND b.kmh >= 30 THEN 'Warning'\r\n              ELSE 'Normal'\r\n            END AS series\r\n          FROM bearing b\r\n        )\r\n        SELECT \r\n          category,\r\n          COUNT(*) AS value,\r\n          series\r\n        FROM events_with_severity\r\n        GROUP BY category, series\r\n        ORDER BY category, series"
        },
        "verify": {
          "max_rows": 1000
        },
        "dataset": {
          "shape": "category_value",
          "columns": {
            "value": {
              "type": "integer"
            },
            "series": {
              "type": "string"
            },
            "category": {
              "type": "date"
            }
          }
        },
        "visualization": {
          "stacking": "percent",
          "colorPalette": "classic"
        }
      }
    },
    {
      "id": 16,
      "type": "stat",
      "title": "Всего событий холостого хода",
      "gridPos": {
        "h": 5,
        "w": 8,
        "x": 0,
        "y": 36
      },
      "options": {
        "textMode": "auto"
      },
      "x-navixy": {
        "sql": {
          "params": {},
          "statement": "WITH ign AS (\r\n          SELECT device_id,\r\n                 device_time,\r\n                 value::int AS ign_on\r\n          FROM raw_telematics_data.states\r\n          WHERE state_name = 'Зажигание'\r\n        ),\r\n        spd AS (\r\n          SELECT device_id, device_time, speed/100.0 AS kmh\r\n          FROM raw_telematics_data.tracking_data_core\r\n        ),\r\n        merged AS (\r\n          SELECT i.device_id,\r\n                 i.device_time,\r\n                 i.ign_on,\r\n                 s.kmh,\r\n                 LEAD(i.device_time) OVER (PARTITION BY i.device_id ORDER BY i.device_time) AS next_time\r\n          FROM ign i\r\n          LEFT JOIN spd s ON s.device_id = i.device_id AND s.device_time = i.device_time\r\n        )\r\n        SELECT COUNT(*) AS value\r\n        FROM merged m\r\n        WHERE m.ign_on = 1 \r\n          AND (m.kmh IS NULL OR m.kmh < 5) \r\n          AND m.next_time IS NOT NULL\r\n          AND EXTRACT(EPOCH FROM (m.next_time - m.device_time))/60 >= 5"
        },
        "verify": {
          "max_rows": 1000
        },
        "dataset": {
          "shape": "kpi",
          "columns": {}
        }
      }
    },
    {
      "id": 9,
      "type": "timeseries",
      "title": "Сообщения с течением времени",
      "gridPos": {
        "h": 13,
        "w": 24,
        "x": 0,
        "y": 83
      },
      "options": {
        "legend": {
          "calcs": [],
          "placement": "bottom",
          "showLegend": true,
          "displayMode": "list"
        },
        "tooltip": {
          "mode": "single",
          "sort": "none"
        }
      },
      "targets": [],
      "x-navixy": {
        "sql": {
          "params": {},
          "statement": "WITH bounds AS (\nSELECT date_trunc('hour', NOW() - INTERVAL '24 hours') AS start_ts, date_trunc('hour', NOW()) AS end_ts ), hours AS (\nSELECT generate_series( (\nSELECT start_ts\nFROM bounds), (\nSELECT end_ts\nFROM bounds), INTERVAL '1 hour' ) AS bucket ), counts AS (\nSELECT date_trunc('hour', t.device_time) AS bucket, COUNT(*) AS messages, COUNT(DISTINCT t.device_id) AS unique_devices\nFROM raw_telematics_data.tracking_data_core t --\n    JOIN raw_business_data.objects o\n  ON o.device_id = t.device_id --\n  AND o.client_id = 398286 -- uncomment & set if you want a specific client\nWHERE t.device_time >= (\nSELECT start_ts\nFROM bounds)\n  AND t.device_time < (\nSELECT end_ts\nFROM bounds) + INTERVAL '1 hour'\nGROUP BY 1 )\nSELECT h.bucket AS time, COALESCE(c.messages, 0) AS messages, COALESCE(c.unique_devices, 0) AS unique_devices\nFROM hours h LEFT\n    JOIN counts c USING (bucket)\nORDER BY time;"
        },
        "verify": {
          "max_rows": 1000
        },
        "dataset": {
          "shape": "time_value",
          "columns": {}
        },
        "visualization": {
          "lineStyle": "solid",
          "colorPalette": "modern",
          "interpolation": "smooth",
          "legendPosition": "top"
        }
      },
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "stacking": {
              "mode": "none",
              "группа": "A"
            },
            "drawStyle": "line",
            "lineWidth": 1,
            "spanNulls": false,
            "showPoints": "auto",
            "fillOpacity": 10,
            "gradientMode": "none",
            "axisPlacement": "auto",
            "lineInterpolation": "linear"
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      }
    },
    {
      "id": 1,
      "type": "kpi",
      "title": "Количество образцов",
      "gridPos": {
        "h": 5,
        "w": 6,
        "x": 18,
        "y": 128
      },
      "options": {
        "textMode": "auto",
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto"
      },
      "targets": [],
      "x-navixy": {
        "sql": {
          "params": {
            "tenant_id": {
              "type": "uuid"
            }
          },
          "statement": "SELECT *\nFROM raw_telematics_data.tracking_data_core LIMIT 10;"
        },
        "verify": {
          "max_rows": 1
        },
        "dataset": {
          "shape": "kpi",
          "columns": {
            "value": {
              "type": "number"
            }
          }
        }
      },
      "datasource": null,
      "description": "",
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "color": {
            "mode": "thresholds"
          },
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      }
    },
    {
      "id": 2,
      "type": "barchart",
      "title": "Образцы данных по категориям",
      "gridPos": {
        "h": 15,
        "w": 18,
        "x": 0,
        "y": 130
      },
      "options": {
        "valueMode": "color",
        "displayMode": "gradient",
        "orientation": "horizontal",
        "showUnfilled": true
      },
      "targets": [],
      "x-navixy": {
        "sql": {
          "params": {},
          "statement": "SELECT o.object_label, COUNT(*) AS msgs_24h\nFROM raw_telematics_data.tracking_data_core AS t\n    JOIN raw_business_data.objects AS o\n  ON o.device_id = t.device_id\nWHERE t.device_time >= NOW() - INTERVAL '24 hours'\nGROUP BY o.client_id, o.object_label, t.device_id\nORDER BY msgs_24h DESC LIMIT 20;"
        },
        "verify": {
          "max_rows": 10
        },
        "dataset": {
          "shape": "category_value",
          "columns": {}
        },
        "visualization": {
          "orientation": "vertical"
        }
      },
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "unit": "short",
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "hideFrom": {
              "viz": false,
              "legend": false,
              "tooltip": false
            }
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      }
    },
    {
      "id": 3,
      "type": "table",
      "title": "Сообщения в день",
      "gridPos": {
        "h": 9,
        "w": 12,
        "x": 4,
        "y": 148
      },
      "options": {
        "sortBy": [],
        "showHeader": true
      },
      "targets": [],
      "x-navixy": {
        "sql": {
          "params": {
            "__to": null,
            "__from": null
          },
          "statement": "SELECT TO_CHAR(date_trunc('day', t.device_time), 'Mon DD, YYYY') AS \"Date\", \n       COUNT(*) AS \"Сообщения\"\nFROM raw_telematics_data.tracking_data_core AS t\nWHERE t.device_time >= ${__from}\n  AND t.device_time < ${__to}\nGROUP BY 1\nORDER BY 1;"
        },
        "verify": {
          "max_rows": 10
        },
        "dataset": {
          "shape": "table",
          "columns": {}
        },
        "visualization": {
          "pageSize": 5
        }
      },
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "custom": {
            "align": "auto",
            "displayMode": "auto"
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      }
    },
    {
      "id": 6,
      "type": "kpi",
      "title": "Общее время простоя",
      "gridPos": {
        "h": 5,
        "w": 8,
        "x": 8,
        "y": 36
      },
      "options": {
        "textMode": "auto"
      },
      "x-navixy": {
        "sql": {
          "params": {},
          "statement": "WITH ign AS (\n    SELECT device_id,\n            device_time,\n            value::int AS ign_on\n    FROM raw_telematics_data.states\n    WHERE state_name = 'Зажигание'\n  ),\n  spd AS (\n    SELECT device_id, device_time, speed/100 AS kmh\n    FROM raw_telematics_data.tracking_data_core\n  ),\n  merged AS (\n    SELECT i.device_id,\n            i.device_time,\n            i.ign_on,\n            s.kmh,\n            LEAD(i.device_time) OVER (PARTITION BY i.device_id ORDER BY i.device_time) AS next_time\n    FROM ign i\n    LEFT JOIN spd s ON s.device_id = i.device_id AND s.device_time = i.device_time\n  )\n  SELECT round(COALESCE(SUM(EXTRACT(EPOCH FROM (m.next_time - m.device_time))/60), 0), 0) AS value\n  FROM merged m\n  WHERE m.ign_on = 1 \n    AND (m.kmh IS NULL OR m.kmh < 5) \n    AND m.next_time IS NOT NULL\n    AND EXTRACT(EPOCH FROM (m.next_time - m.device_time))/60 >= 5"
        },
        "verify": {
          "max_rows": 1000
        },
        "dataset": {
          "shape": "kpi",
          "columns": {
            "value": {
              "type": "number"
            }
          }
        }
      }
    },
    {
      "id": 7,
      "type": "piechart",
      "title": "Самые активные устройства за последние 24h",
      "gridPos": {
        "h": 9,
        "w": 12,
        "x": 0,
        "y": 121
      },
      "options": {
        "pieType": "donut"
      },
      "x-navixy": {
        "sql": {
          "params": {},
          "statement": "SELECT o.object_label, COUNT(*) AS msgs_24h\nFROM raw_telematics_data.tracking_data_core AS t\n    JOIN raw_business_data.objects AS o\n  ON o.device_id = t.device_id\nWHERE t.device_time >= NOW() - INTERVAL '24 hours'\nGROUP BY o.client_id, o.object_label, t.device_id\nORDER BY msgs_24h DESC LIMIT 20;"
        },
        "verify": {
          "max_rows": 1000
        },
        "dataset": {
          "shape": "pie",
          "columns": {}
        }
      }
    },
    {
      "id": 8,
      "type": "table",
      "title": "Последние перемещения транспортных средств",
      "gridPos": {
        "h": 25,
        "w": 24,
        "x": 0,
        "y": 96
      },
      "options": {
        "showHeader": true
      },
      "x-navixy": {
        "sql": {
          "params": {},
          "statement": "SELECT\n  to_char(t.device_time, 'YYYY-MM-DD HH24:MI:SS TZ') AS \"Timestamp\",\n  t.device_id                                       AS \"Device ID\",\n  t.speed                                           AS \"Speed\",\n  round(t.latitude::numeric  / 10000000, 6)         AS \"Latitude (°)\",\n  round(t.longitude::numeric / 10000000, 6)         AS \"Longitude (°)\"\nFROM raw_telematics_data.tracking_data_core t\nWHERE t.device_time >= NOW() - INTERVAL '3 days'\n  AND t.speed > 0\nORDER BY t.device_time DESC;"
        },
        "verify": {
          "max_rows": 3
        },
        "dataset": {
          "shape": "table",
          "columns": {
            "Speed": {
              "type": "integer"
            },
            "Идентификатор устройства": {
              "type": "integer"
            },
            "Временная метка": {
              "type": "string"
            },
            "Широта (°)": {
              "type": "number"
            },
            "Долгота (°)": {
              "type": "number"
            }
          }
        },
        "visualization": {
          "pageSize": 25,
          "sortable": true,
          "showHeader": true,
          "showTotals": false,
          "rowHighlighting": "hover"
        }
      }
    },
    {
      "id": 19,
      "type": "stat",
      "title": "Средняя продолжительность простоя",
      "gridPos": {
        "h": 5,
        "w": 8,
        "x": 16,
        "y": 36
      },
      "options": {
        "textMode": "auto"
      },
      "x-navixy": {
        "sql": {
          "params": {},
          "statement": "WITH ign AS (\r\n          SELECT device_id,\r\n                 device_time,\r\n                 value::int AS ign_on\r\n          FROM raw_telematics_data.states\r\n          WHERE state_name = 'Зажигание'\r\n        ),\r\n        spd AS (\r\n          SELECT device_id, device_time, speed/100.0 AS kmh\r\n          FROM raw_telematics_data.tracking_data_core\r\n        ),\r\n        merged AS (\r\n          SELECT i.device_id,\r\n                 i.device_time,\r\n                 i.ign_on,\r\n                 s.kmh,\r\n                 LEAD(i.device_time) OVER (PARTITION BY i.device_id ORDER BY i.device_time) AS next_time\r\n          FROM ign i\r\n          LEFT JOIN spd s ON s.device_id = i.device_id AND s.device_time = i.device_time\r\n        )\r\n        SELECT round(COALESCE(AVG(EXTRACT(EPOCH FROM (m.next_time - m.device_time))/60), 0),0) AS value\r\n        FROM merged m\r\n        WHERE m.ign_on = 1 \r\n          AND (m.kmh IS NULL OR m.kmh < 5) \r\n          AND m.next_time IS NOT NULL\r\n          AND EXTRACT(EPOCH FROM (m.next_time - m.device_time))/60 >= 5"
        },
        "verify": {
          "max_rows": 1000
        },
        "dataset": {
          "shape": "kpi",
          "columns": {}
        }
      }
    }
  ],
  "refresh": "30s",
  "version": 1,
  "editable": true,
  "timezone": "browser",
  "x-navixy": {
    "execution": {
      "dialect": "postgresql",
      "endpoint": "/api/v1/sql/run",
      "max_rows": 1000,
      "read_only": true,
      "timeout_ms": 5000,
      "allowed_schemas": [
        "demo_data"
      ]
    },
    "parameters": {
      "bindings": {
        "to": "${__to}",
        "from": "${__from}",
        "tenant_id": "${var_tenant}"
      }
    },
    "schemaVersion": "1.0.0"
  },
  "templating": {
    "list": [
      {
        "name": "var_tenant",
        "type": "constant",
        "label": "Tenant",
        "query": "demo-tenant-id",
        "current": {
          "text": "Demo Tenant",
          "value": "demo-tenant-id"
        },
        "options": [
          {
            "text": "Demo Tenant",
            "value": "demo-tenant-id",
            "selected": true
          }
        ]
      }
    ],
    "enable": true
  },
  "timepicker": {
    "now": true,
    "enable": true,
    "hidden": false,
    "collapse": false,
    "time_options": [
      "5m",
      "15m",
      "1h",
      "6h",
      "12h",
      "24h"
    ],
    "refresh_intervals": [
      "5s",
      "10s",
      "30s",
      "1m",
      "5m",
      "15m",
      "30m",
      "1h"
    ]
  },
  "annotations": {
    "list": [
      {
        "hide": true,
        \"name\": \"Аннотации и Контроль событий\",
        "type": "dashboard",
        "enable": true,
        "target": {
          "tags": [],
          "type": "dashboard",
          "limit": 100,
          "matchAny": false
        },
        "builtIn": 1,
        "iconColor": "rgba(0, 211, 255, 1)",
        "datasource": {
          "uid": "-- Dashboard --",
          "type": "dashboard"
        }
      }
    ]
  },
  "description": "Simple getting started example dashboard",
  "graphTooltip": 1,
  "schemaVersion": 38
}
```

{% endcode %}

Чтобы узнать больше о приложении панели мониторинга IoT Query, см. [Dashboard Studio](/docs/analytics/ru/dashboard-studio.md).

За помощью в настройке обратитесь к <iotquery@navixy.com>.

## **Контроль событий об истечении срока регистрации / Страховка**

Банки должны отслеживать предстоящие сроки окончания регистрации и Страховка, потому что они отвечают за технические осмотры, регистрацию и Страховка. Своевременные оповещения помогают избежать штрафов и простоя транспортных средств.

{% code expandable="true" %}

```sql
SELECT 
    v.vehicle_id,
    v.vehicle_label,
    v.registration_number,
    v.free_Страховка_valid_till_date,
    v.liability_Страховка_valid_till
FROM raw_business_data.Транспорт v
WHERE v.free_insurance_valid_till_date BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '30 days'
    OR v.liability_insurance_valid_till BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '30 days';
```

{% endcode %}

## **Истечение срока действия водительских прав**

Хотя это не всегда обязательно, предложение проактивного сервиса Контроль событий об истечении срока действия лицензии является дополнительной ценностью. Ранние предупреждения позволяют клиентам продлевать лицензии до их истечения. Обратите внимание, что вы

{% code expandable="true" %}

```sql
SELECT e.employee_id,
       e.first_name || ' ' || e.last_name AS driver_name,
       e.driver_license_number,
       e.driver_license_valid_till
FROM raw_business_data.employees e
WHERE e.driver_license_valid_till BETWEEN CURRENT_DATE AND CURRENT_DATE + (30 * INTERVAL '1 day');
```

{% endcode %}

## Выход из геозоны (граница страны) <a href="#geofence-exit-country-border" id="geofence-exit-country-border"></a>

Контракты могут ограничивать Движение транспортного средства определенной территорией (например, Сербией). Выезд из этой зоны должен немедленно оповещать банк, чтобы он мог принять меры (например, связаться с клиентом, обездвижить Актив).

Этот SQL-запрос предназначен для отслеживания и определения момента, когда устройство покидает заранее заданную географическую зону с меткой "Tallaght Гараж Geofences." Процесс начинается со сбора и упорядочивания географических точек, которые определяют границу зоны. Чтобы гарантировать, что граница образует корректный полигон, первая точка добавляется в конец списка, фактически замыкая фигуру. Затем этот замкнутый набор точек используется для создания полигона, представляющего географическую зону, который преобразуется в объект geography для пространственного анализа.

Запрос затем извлекает данные мониторинга устройства за указанный временной диапазон, преобразуя необработанные значения широты и долготы в географические точки. Он вычисляет, находится ли каждая точка устройства внутри или вне предопределенной зоны, используя функцию ST\_Contains, которая проверяет пространственное включение. Рассчитанный параметр pos принимает значение 'inside', если точка находится в зоне, и 'outside' в противном случае. Наконец, запрос фильтрует эти результаты, чтобы обнаружить переходы, когда устройство перемещается из зоны внутрь в зону наружу, используя оконную функцию для сравнения текущего положения с предыдущим. Эта логика помогает в мониторинге перемещений устройства и обнаружении событий выезда из конкретных географических областей. Убедитесь, что вы добавили правильное значение для параметра: `z.zone_label = 'your_zone_label'.`

{% code expandable="true" %}

```sql
WITH zone AS (
  SELECT z.zone_id,
         ST_MakePolygon(ST_MakeLine(ARRAY_AGG(ST_MakePoint(g.longitude, g.latitude) ORDER BY g.number)))::geography AS geog
  FROM raw_business_data.zones z
  JOIN raw_business_data.geofence_points g ON g.zone_id = z.zone_id
  WHERE z.zone_label = 'your_zone_label'
  Группа BY z.zone_id
),
pts AS (
  SELECT device_id,
         device_time,
         ST_SetSRID(ST_MakePoint(longitude/1e7::numeric, latitude/1e7::numeric), 4326)::geography AS geog
  FROM raw_telematics_data.tracking_data_core
  WHERE device_time BETWEEN '2025-07-27 00:00:00' AND '2025-07-28 23:59:59'
),
states AS (
  SELECT p.*,
         CASE WHEN ST_Contains(z.geog::geometry, p.geog::geometry) THEN 'inside' ELSE 'outside' END AS pos
  FROM pts p CROSS JOIN zone z
),
filtered_states AS (
  SELECT
    device_id,
    device_time,
    pos,
    LAG(pos) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_pos
  FROM states
)
SELECT device_id, device_time, pos
FROM filtered_states
WHERE prev_pos = 'inside' AND pos = 'outside';

```

{% endcode %}

## **Регулярные проверки по временному интервалу**

Некоторые Задания по Техобслуживанию повторяются по фиксированному графику. Система должна помечать Транспорт, у которого следующая проверка/осмотр должна быть выполнена в пределах заданного интервала.

{% code expandable="true" %}

```sql
WITH t AS (
    SELECT
        vehicle_id,
        description,
        start_date,
        date_repeat_interval,
        make_interval(days => date_repeat_interval) AS repeat_interval
    ИЗ исходных данных vehicle_service_tasks
    WHERE date_repeat_interval IS NOT NULL
)
SELECT
    vehicle_id,
    description,
    start_date,
    date_repeat_interval,
    start_date
        + repeat_interval
            * floor(
                extract(epoch from (current_date::timestamp - start_date))
                / extract(epoch from repeat_interval)
              ) AS last_due,
    start_date
        + repeat_interval
            * (
                floor(
                    extract(epoch from (current_date::timestamp - start_date))
                    / extract(epoch from repeat_interval)
                ) + 1
              ) AS next_due
FROM t
WHERE (
        start_date
            + repeat_interval
                * (
                    floor(
                        extract(epoch from (current_date::timestamp - start_date))
                        / extract(epoch from repeat_interval)
                    ) + 1
                  )
      ) BETWEEN current_date
          AND (current_date + interval '30 days');
```

{% endcode %}

## **Обслуживание по порогу Пробег (малый/большой)**

Малое и крупное обслуживание запускаются по Пробегу с момента последнего события обслуживания. Когда накопленный пробег превышает порог, необходимо запланировать соответствующее обслуживание.

Обратите внимание на `Поле vst.description должно содержать соответствующие комментарии / описание, чтобы использовать его для фильтров в SQL-коде ниже.`

{% code expandable="true" %}

```sql
SELECT
  v.vehicle_id,
  v.vehicle_label,
  km.km_since_service,
  vst.mileage_limit
FROM
  raw_business_data.Транспорт v
  JOIN LATERAL (
    SELECT MAX(vst.completion_date) AS last_service_date
    ИЗ raw_business_data.vehicle_service_tasks vst
    WHERE vst.vehicle_id = v.vehicle_id
      AND (vst.description ILIKE '%minor%' OR vst.description ILIKE '%major%')
      AND vst.completion_date IS NOT NULL
  ) ls ON TRUE
  JOIN raw_business_data.objects o ON o.object_id = v.vehicle_id
  JOIN LATERAL (
    SELECT SUM(t.trip_distance_meters) / 1000.0 AS km_since_service
    FROM processed_common_data.trips t
    WHERE t.device_id = o.device_id
      AND t.trip_start_time > ls.last_service_date
  ) км ON TRUE
  JOIN raw_business_data.vehicle_service_tasks vst
    ON vst.vehicle_id = v.vehicle_id
    AND vst.completion_date = ls.last_service_date
    AND (vst.description ILIKE '%minor%' OR vst.description ILIKE '%major%')

```

{% endcode %}

## **Лимит пробега и штрафы**

В договорах лизинга часто устанавливается ограничение на Пробег (например, 25,000 km/year). Если лимит превышен, применяются штрафные условия. Система должна сравнивать фактический Пробег за период действия договора с согласованным лимитом и рассчитывать сборы.

{% code expandable="true" %}

```sql
WITH driven AS (
  SELECT
    o.object_id,
    DATE_TRUNC('year', t.trip_start_time) AS year,
    SUM(t.trip_distance_meters) / 1000.0 AS km_year
  FROM
    processed_common_data.Поездки t
    JOIN raw_business_data.objects o ON o.device_id = t.device_id
  WHERE
    t.trip_start_time >= '2023-01-01'::date
    AND t.trip_start_time < '2024-01-01'::date
  ГРУППА ПО
    o.object_id, DATE_TRUNC('year', t.trip_start_time)
),
limits AS (
  SELECT
    object_id,
    10000 AS km_limit,
    0.5 AS penalty_rate
  FROM
    raw_business_data.objects
)
SELECT
  d.object_id,
  d.year,
  d.km_year,
  l.km_limit,
  GREATEST(d.km_year - l.km_limit, 0) AS km_over,
  GREATEST(d.km_year - l.km_limit, 0) * l.penalty_rate AS penalty_amount
FROM
  пройдено d
  JOIN limits l ON d.object_id = l.object_id;
```

{% endcode %}

## **Мониторинг моточасов**

Для машин и сельскохозяйственного оборудования часы работы — а не Пробег — определяют Техобслуживание и биллинг. Данные по моточасам (например, из CAN-Bus) необходимо отслеживать и сводить.

{% code expandable="true" %}

```sql
WITH last_service AS (
  SELECT
    vst.vehicle_id,
    MAX(vst.completion_date) AS last_service_date,
    MAX(vst.completion_engine_hours) AS last_service_engine_hours
  FROM
    raw_business_data.vehicle_service_tasks vst
  ГРУППА ПО
    vst.vehicle_id
),
engine_hours_since_service AS (
  SELECT
    v.vehicle_id,
    SUM(t.trip_duration_seconds) / 3600.0 AS engine_hours_since_service
  FROM
    raw_business_data.Транспорт v
    JOIN raw_business_data.objects o ON o.object_id = v.object_id
    JOIN processed_common_data.trips t ON t.device_id = o.device_id
    JOIN last_service ls ON ls.vehicle_id = v.vehicle_id
  WHERE
    t.trip_start_time > ls.last_service_date
  ГРУППА ПО
    v.vehicle_id
)
SELECT
  v.vehicle_id,
  v.vehicle_label,
  ls.last_service_engine_hours,
  ehs.engine_hours_since_service,
  (COALESCE(ehs.engine_hours_since_service,0) + COALESCE(ls.last_service_engine_hours,0)) AS current_engine_hours,
  vst.engine_hours_limit
FROM
  raw_business_data.Транспорт v
  JOIN last_service ls ON ls.vehicle_id = v.vehicle_id
  LEFT JOIN engine_hours_since_service ehs ON ehs.vehicle_id = v.vehicle_id
  JOIN raw_business_data.vehicle_service_tasks vst
    ON vst.vehicle_id = v.vehicle_id
    AND vst.completion_date = ls.last_service_date
```

{% endcode %}

## **События торможения**

Поведение при вождении влияет на износ и соблюдение условий договора. Обнаружение торможения помогает банку отнести преждевременный износ тормозов/шин на счет неправильного использования водителем и, при необходимости, переложить затраты.

Приведенный ниже SQL-запрос сначала вычисляет скорость в километрах в час и разницу во времени между последовательными точками данных для каждого устройства. Используя эту информацию, он затем вычисляет скорость замедления в километрах в час в секунду. Наконец, он фильтрует и возвращает записи, где скорость замедления составляет 20 км/ч в секунду или выше, что указывает на значительные события замедления.

{% code expandable="true" %}

```sql
WITH spd AS (
  SELECT
    device_id,
    device_time,
    speed/100.0 AS kmh,
    LAG(speed/100.0) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_kmh,
    EXTRACT(EPOCH FROM (device_time - LAG(device_time) OVER (PARTITION BY device_id ORDER BY device_time))) AS dt_sec
  FROM
    raw_telematics_data.tracking_data_core
  WHERE
    device_time BETWEEN '2025-07-24 00:00:00' AND '2025-07-24 23:59:59'
),
decels AS (
  SELECT
    device_id,
    device_time,
    (prev_kmh - kmh) / NULLIF(dt_sec, 0) AS decel_kmh_per_sec
  FROM
    spd
  WHERE
    prev_kmh IS NOT NULL
)
SELECT *
FROM decels
WHERE decel_kmh_per_sec >= 20;
```

{% endcode %}

## **События Ускорение**

Резкое ускорение увеличивает износ шин, трансмиссий, приводных систем и опор двигателя. Выявление этих событий помогает коучингу и потенциальному возмещению затрат.

Ниже приведенный SQL-запрос предназначен для выявления значимых событий ускорения в наборе данных мониторинга. Сначала он вычисляет скорость в километрах в час и разницу во времени между последовательными точками данных для каждого устройства. Затем на основе этой информации он рассчитывает скорость ускорения в километрах в час в секунду. Наконец, он фильтрует и возвращает записи, где скорость ускорения достигает или превышает заданный порог, что указывает на значимые события ускорения.

{% code expandable="true" %}

```sql
WITH spd AS (
  SELECT
    device_id,
    device_time,
    speed/100.0 AS kmh,
    LAG(speed/100.0) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_kmh,
    EXTRACT(EPOCH FROM (device_time - LAG(device_time) OVER (PARTITION BY device_id ORDER BY device_time))) AS dt_sec
  FROM
    raw_telematics_data.tracking_data_core
  WHERE
    device_time BETWEEN '2025-07-28 00:00:00' AND '2025-07-28 23:59:59'
)
SELECT
  device_id,
  device_time,
  (kmh - prev_kmh) / NULLIF(dt_sec, 0) AS accel_kmh_per_sec
FROM
  spd
WHERE
  prev_kmh IS NOT NULL
  AND (kmh - prev_kmh) / NULLIF(dt_sec, 0) >= 20;
```

{% endcode %}

## **Резкие повороты / прохождение поворотов**

Резкие повороты в сочетании с внезапными изменениями скорости указывают на рискованное вождение. Мониторинг такого поведения помогает выявлять ненадлежащее использование транспортного средства.

Этот SQL-запрос предназначен для выявления значительных изменений направления и скорости по данным мониторинга за указанный период времени. Сначала он преобразует исходные значения широты и долготы в десятичные градусы и вычисляет скорость в километрах в час. Используя функцию LAG, он получает предыдущие данные о местоположении и скорости для каждого устройства, что позволяет вычислять изменения во времени. Затем запрос вычисляет изменение курса в градусах с помощью тригонометрических функций, чтобы определить азимут между последовательными точками. Он также вычисляет изменение скорости между этими точками. Наконец, запрос отфильтровывает результаты, оставляя только те записи, где абсолютное изменение курса составляет 10 градусов или более, а абсолютное изменение скорости - 5 км/ч или более, выявляя значимые маневры или события в данных мониторинга.

{% code expandable="true" %}

```sql
WITH pts AS (
  SELECT
    device_id,
    device_time,
    latitude/1e7::numeric AS lat,
    longitude/1e7::numeric AS lon,
    LAG(latitude/1e7::numeric) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_lat,
    LAG(longitude/1e7::numeric) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_lon,
    speed/100.0 AS kmh,
    LAG(speed/100.0) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_kmh
  FROM
    raw_telematics_data.tracking_data_core
  WHERE
    device_time BETWEEN '2025-07-28 00:00:00' AND '2025-07-28 23:59:59'
),
bearing AS (
  SELECT *,
         atan2(
           sin(radians(lon-prev_lon))*cos(radians(lat)),
           cos(radians(prev_lat))*sin(radians(lat)) -
           sin(radians(prev_lat))*cos(radians(lat))*cos(radians(lon-prev_lon))
         ) * 180/pi() AS heading_change,
         (kmh - prev_kmh) AS delta_speed
  FROM pts
)
SELECT *
FROM bearing
WHERE abs(heading_change) >= 10
  AND abs(delta_speed) >= 5;

```

{% endcode %}

## **Зажигание и определение работы на холостом ходу**

Измерение времени простоя (зажигание включено, низкая скорость или отсутствие движения) помогает сократить перерасход топлива и выявлять нецелевое использование. Длительные периоды работы на холостом ходу следует фиксировать и контролировать.

{% hint style="info" %}
[Dashboard Studio](/docs/analytics/ru/dashboard-studio.md) и аналогичные инструменты не поддерживают подстановку переменных (`:variable` синтаксис). Замените все параметры буквальными значениями перед выполнением этого запроса. См. пример ниже для правильного формата.
{% endhint %}

{% code expandable="true" %}

```sql
WITH ign AS (
    SELECT
        device_id,
        device_time,
        value::int AS ign_on
    FROM raw_telematics_data.states
    WHERE state_name = 'Зажигание'
      AND device_time BETWEEN :from_ts::timestamptz AND :to_ts::timestamptz
      -- Для Dashboard Studio замените :from_ts и :to_ts на буквальные метки времени:
      -- TIMESTAMPTZ '2024-01-01 00:00:00+00' AND TIMESTAMPTZ '2024-01-07 00:00:00+00'
),
spd AS (
    SELECT
        device_id,
        device_time,
        speed / 100.0 AS kmh
    FROM raw_telematics_data.tracking_data_core
    WHERE device_time BETWEEN :from_ts AND :to_ts
    -- Для Dashboard Studio замените :from_ts и :to_ts на буквальные метки времени:
    -- TIMESTAMPTZ '2024-01-01 00:00:00+00' AND TIMESTAMPTZ '2024-01-07 00:00:00+00'
),
merged AS (
    SELECT
        i.device_id,
        i.device_time,
        i.ign_on,
        s.kmh,
        LEAD(i.device_time) OVER (
            PARTITION BY i.device_id
            ORDER BY i.device_time
        ) AS next_time
    FROM ign i
    LEFT JOIN spd s USING (device_id, device_time)
)
SELECT
    device_id,
    device_time AS idle_start,
    next_time   AS idle_end,
    EXTRACT(EPOCH FROM (next_time - device_time)) / 60.0 AS idle_minutes
FROM merged
WHERE ign_on = 1
  AND kmh < :idle_speed
  -- Для Dashboard Studio замените :idle_speed на числовое значение, например 5
  AND next_time IS NOT NULL
  AND (next_time - device_time) >= (:idle_min::int * INTERVAL '1 minute');
  -- Для Dashboard Studio замените :idle_min на числовое значение, например (5 * INTERVAL '1 minute')
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://navixy.com/docs/analytics/ru/example-queries/leasing.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
