← Назад к вопросам

Что такое тикет-система в БД?

2.3 Middle🔥 41 комментариев
#Python Core#Базы данных (SQL)

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Тикет-система в БД (Ticket System in Database)

Тикет-система в БД — это совокупность механизмов и структур данных, используемых для управления и отслеживанием заявок, задач или проблем (тикетов) в системе. Тикет обычно содержит информацию о проблеме, её статусе, приоритете, отправителе и других метаданных. Это фундаментальная часть систем управления проектами, систем поддержки клиентов и workflow-приложений.

Основная структура данных

1. Базовая таблица тикетов

from datetime import datetime
from enum import Enum
from typing import Optional

class TicketStatus(Enum):
    OPEN = "open"
    IN_PROGRESS = "in_progress"
    RESOLVED = "resolved"
    CLOSED = "closed"
    REOPENED = "reopened"

class TicketPriority(Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"

class Ticket:
    def __init__(
        self,
        id: int,
        title: str,
        description: str,
        status: TicketStatus,
        priority: TicketPriority,
        created_at: datetime,
        created_by: int,  # user_id
        assigned_to: Optional[int] = None,
        updated_at: datetime = None,
    ):
        self.id = id
        self.title = title
        self.description = description
        self.status = status
        self.priority = priority
        self.created_at = created_at
        self.created_by = created_by
        self.assigned_to = assigned_to
        self.updated_at = updated_at or created_at

2. SQL-схема тикет-системы

# SQL DDL (Data Definition Language)
sql_schema = """
CREATE TABLE tickets (
    id SERIAL PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    description TEXT NOT NULL,
    status VARCHAR(50) NOT NULL DEFAULT 'open',
    priority VARCHAR(50) NOT NULL DEFAULT 'medium',
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by INTEGER NOT NULL REFERENCES users(id),
    assigned_to INTEGER REFERENCES users(id),
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    resolved_at TIMESTAMP,
    resolution_notes TEXT,
    CONSTRAINT valid_status CHECK (status IN ('open', 'in_progress', 'resolved', 'closed', 'reopened')),
    CONSTRAINT valid_priority CHECK (priority IN ('low', 'medium', 'high', 'critical'))
);

CREATE TABLE ticket_comments (
    id SERIAL PRIMARY KEY,
    ticket_id INTEGER NOT NULL REFERENCES tickets(id) ON DELETE CASCADE,
    author_id INTEGER NOT NULL REFERENCES users(id),
    content TEXT NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE ticket_history (
    id SERIAL PRIMARY KEY,
    ticket_id INTEGER NOT NULL REFERENCES tickets(id) ON DELETE CASCADE,
    changed_by INTEGER NOT NULL REFERENCES users(id),
    field_name VARCHAR(100) NOT NULL,
    old_value TEXT,
    new_value TEXT,
    changed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE ticket_tags (
    id SERIAL PRIMARY KEY,
    ticket_id INTEGER NOT NULL REFERENCES tickets(id) ON DELETE CASCADE,
    tag VARCHAR(100) NOT NULL,
    UNIQUE(ticket_id, tag)
);

CREATE INDEX idx_ticket_status ON tickets(status);
CREATE INDEX idx_ticket_assigned_to ON tickets(assigned_to);
CREATE INDEX idx_ticket_created_by ON tickets(created_by);
CREATE INDEX idx_ticket_priority ON tickets(priority);
"""

Операции с тикетами

1. Создание тикета

import psycopg2
from datetime import datetime

def create_ticket(
    connection,
    title: str,
    description: str,
    created_by: int,
    priority: str = "medium"
) -> int:
    """Создаёт новый тикет и возвращает его ID"""
    cursor = connection.cursor()
    
    query = """
        INSERT INTO tickets (title, description, status, priority, created_by, created_at)
        VALUES (%s, %s, %s, %s, %s, %s)
        RETURNING id;
    """
    
    cursor.execute(query, (
        title,
        description,
        "open",
        priority,
        created_by,
        datetime.now()
    ))
    
    ticket_id = cursor.fetchone()[0]
    connection.commit()
    cursor.close()
    
    return ticket_id

2. Обновление статуса

def update_ticket_status(
    connection,
    ticket_id: int,
    new_status: str,
    updated_by: int,
    resolution_notes: str = None
):
    """Обновляет статус тикета и создаёт запись в истории"""
    cursor = connection.cursor()
    
    # Получаем старый статус
    cursor.execute("SELECT status FROM tickets WHERE id = %s", (ticket_id,))
    old_status = cursor.fetchone()[0]
    
    # Обновляем статус
    resolved_at = datetime.now() if new_status == "resolved" else None
    
    update_query = """
        UPDATE tickets
        SET status = %s, updated_at = %s, resolved_at = %s, resolution_notes = %s
        WHERE id = %s;
    """
    
    cursor.execute(update_query, (
        new_status,
        datetime.now(),
        resolved_at,
        resolution_notes,
        ticket_id
    ))
    
    # Создаём запись в истории
    history_query = """
        INSERT INTO ticket_history (ticket_id, changed_by, field_name, old_value, new_value)
        VALUES (%s, %s, %s, %s, %s);
    """
    
    cursor.execute(history_query, (
        ticket_id,
        updated_by,
        "status",
        old_status,
        new_status
    ))
    
    connection.commit()
    cursor.close()

3. Назначение тикета

def assign_ticket(connection, ticket_id: int, assigned_to: int, assigned_by: int):
    """Назначает тикет сотруднику"""
    cursor = connection.cursor()
    
    # Получаем текущего исполнителя
    cursor.execute("SELECT assigned_to FROM tickets WHERE id = %s", (ticket_id,))
    old_assigned = cursor.fetchone()[0]
    
    # Обновляем
    cursor.execute(
        "UPDATE tickets SET assigned_to = %s, updated_at = %s WHERE id = %s",
        (assigned_to, datetime.now(), ticket_id)
    )
    
    # История
    cursor.execute(
        """INSERT INTO ticket_history (ticket_id, changed_by, field_name, old_value, new_value)
           VALUES (%s, %s, %s, %s, %s)""",
        (ticket_id, assigned_by, "assigned_to", str(old_assigned), str(assigned_to))
    )
    
    connection.commit()
    cursor.close()

4. Добавление комментария

def add_comment(connection, ticket_id: int, author_id: int, content: str):
    """Добавляет комментарий к тикету"""
    cursor = connection.cursor()
    
    cursor.execute(
        """INSERT INTO ticket_comments (ticket_id, author_id, content, created_at)
           VALUES (%s, %s, %s, %s)""",
        (ticket_id, author_id, content, datetime.now())
    )
    
    # Обновляем время обновления тикета
    cursor.execute(
        "UPDATE tickets SET updated_at = %s WHERE id = %s",
        (datetime.now(), ticket_id)
    )
    
    connection.commit()
    cursor.close()

5. Получение тикета со всеми данными

def get_ticket_full(connection, ticket_id: int) -> dict:
    """Получает тикет со всеми комментариями и историей"""
    cursor = connection.cursor()
    
    # Основная информация
    cursor.execute("""
        SELECT id, title, description, status, priority,
               created_at, created_by, assigned_to, updated_at
        FROM tickets
        WHERE id = %s
    """, (ticket_id,))
    
    ticket = cursor.fetchone()
    
    # Комментарии
    cursor.execute("""
        SELECT id, author_id, content, created_at
        FROM ticket_comments
        WHERE ticket_id = %s
        ORDER BY created_at DESC
    """, (ticket_id,))
    
    comments = cursor.fetchall()
    
    # История
    cursor.execute("""
        SELECT id, changed_by, field_name, old_value, new_value, changed_at
        FROM ticket_history
        WHERE ticket_id = %s
        ORDER BY changed_at DESC
    """, (ticket_id,))
    
    history = cursor.fetchall()
    
    cursor.close()
    
    return {
        "ticket": ticket,
        "comments": comments,
        "history": history
    }

Аналитика и отчёты

1. Статистика по статусам

def get_status_statistics(connection) -> dict:
    """Возвращает количество тикетов по статусам"""
    cursor = connection.cursor()
    
    cursor.execute("""
        SELECT status, COUNT(*) as count
        FROM tickets
        GROUP BY status
        ORDER BY count DESC
    """)
    
    stats = {row[0]: row[1] for row in cursor.fetchall()}
    cursor.close()
    
    return stats

2. Среднее время разрешения

def get_average_resolution_time(connection) -> float:
    """Возвращает среднее время разрешения тикета в часах"""
    cursor = connection.cursor()
    
    cursor.execute("""
        SELECT AVG(EXTRACT(EPOCH FROM (resolved_at - created_at)) / 3600) as avg_hours
        FROM tickets
        WHERE resolved_at IS NOT NULL
    """)
    
    avg_hours = cursor.fetchone()[0]
    cursor.close()
    
    return avg_hours

3. Производительность сотрудника

def get_employee_stats(connection, employee_id: int) -> dict:
    """Возвращает статистику по тикетам сотрудника"""
    cursor = connection.cursor()
    
    cursor.execute("""
        SELECT
            COUNT(*) as total_tickets,
            SUM(CASE WHEN status = 'resolved' THEN 1 ELSE 0 END) as resolved,
            SUM(CASE WHEN status = 'open' THEN 1 ELSE 0 END) as open,
            AVG(EXTRACT(EPOCH FROM (resolved_at - created_at)) / 3600) as avg_resolution_hours
        FROM tickets
        WHERE assigned_to = %s
    """, (employee_id,))
    
    stats = cursor.fetchone()
    cursor.close()
    
    return {
        "total_tickets": stats[0],
        "resolved": stats[1],
        "open": stats[2],
        "avg_resolution_hours": stats[3]
    }

Лучшие практики

  1. Индексирование: добавьте индексы на часто фильтруемые поля (status, assigned_to)
  2. Партиционирование: для больших таблиц используйте партиционирование по дате
  3. Архивирование: архивируйте закрытые тикеты в отдельную таблицу
  4. SLA (Service Level Agreement): отслеживайте время ответа и разрешения
  5. История изменений: сохраняйте полную историю для аудита
  6. Уведомления: отправляйте уведомления при изменении тикета
  7. Поиск: используйте полнотекстовый поиск (FTS) для заголовков и описаний

Тикет-система в БД — это критическая часть любого системы поддержки или управления проектами, обеспечивающая отслеживание, организацию и анализ работы команды.