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

Как добавить ограничение для поля в таблице SQL

2.0 Middle🔥 201 комментариев
#Основы Java

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

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

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

# Как добавить ограничение для поля в таблице SQL

Ограничения (constraints) в SQL — это правила, которые обеспечивают целостность данных в базе. Они гарантируют что данные соответствуют определённым требованиям.

Основные типы ограничений

1. PRIMARY KEY - первичный ключ

-- Определение при создании таблицы
CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    name VARCHAR(255)
);

-- Или явно
CREATE TABLE users (
    id BIGINT,
    email VARCHAR(255) NOT NULL,
    name VARCHAR(255),
    PRIMARY KEY (id)
);

-- Что гарантирует:
-- - Уникальность (нет дублей)
-- - Не NULL
-- - Идентификация записей
-- - Основа для внешних ключей

В Java/Hibernate:

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;  // PRIMARY KEY
    
    private String email;
}

2. UNIQUE - уникальность

-- Поле должно быть уникальным
CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,  -- Каждый email уникален
    phone VARCHAR(20) UNIQUE,
    name VARCHAR(255)
);

-- Или несколько полей вместе уникальны
CREATE TABLE orders (
    id BIGINT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    order_number VARCHAR(50),
    UNIQUE(user_id, order_number)  -- Комбинация уникальна
);

-- Это позволяет:
INSERT INTO users (id, email, name) VALUES (1, 'john@example.com', 'John');
INSERT INTO users (id, email, name) VALUES (2, 'john@example.com', 'Jane');  -- ERROR!
-- Duplicate entry 'john@example.com' for key 'email'

В Java/Hibernate:

@Entity
@Table(name = "users", uniqueConstraints = {
    @UniqueConstraint(columnNames = "email"),
    @UniqueConstraint(columnNames = {"user_id", "order_number"})
})
public class User {
    @Column(unique = true, nullable = false)
    private String email;
}

3. NOT NULL - не пустое значение

CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    email VARCHAR(255) NOT NULL,  -- Обязательное поле
    name VARCHAR(255),             -- Опциональное
    phone VARCHAR(20)
);

-- Это позволяет:
INSERT INTO users (id, name) VALUES (1, 'John');  -- ERROR!
-- Column 'email' cannot be null

INSERT INTO users (id, email, name) VALUES (1, 'john@example.com', 'John');  -- OK

В Java/Hibernate:

@Entity
public class User {
    @Column(nullable = false)
    private String email;  // NOT NULL
    
    private String phone;  // Может быть null
}

4. DEFAULT - значение по умолчанию

CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    is_active BOOLEAN DEFAULT true,  -- Если не указано - true
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,  -- Текущее время
    status VARCHAR(20) DEFAULT 'ACTIVE'
);

-- Использование
INSERT INTO users (id, email) VALUES (1, 'john@example.com');
-- is_active = true (по умолчанию)
-- created_at = 2025-03-22 10:30:00 (текущее время)
-- status = 'ACTIVE'

В Java/Hibernate:

@Entity
public class User {
    @Column(columnDefinition = "BOOLEAN DEFAULT true")
    private Boolean isActive = true;
    
    @Column(columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
    private LocalDateTime createdAt;
    
    @Column(length = 20, columnDefinition = "VARCHAR(20) DEFAULT 'ACTIVE'")
    private String status = "ACTIVE";
}

5. CHECK - проверка условия

CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    age INT CHECK (age >= 18),  -- Возраст должен быть >= 18
    balance DECIMAL(10, 2) CHECK (balance >= 0)  -- Баланс неотрицательный
);

-- Это позволяет:
INSERT INTO users (id, email, age) VALUES (1, 'john@example.com', 17);  -- ERROR!
-- Check constraint 'age >= 18' violated

INSERT INTO users (id, email, age) VALUES (1, 'john@example.com', 25);  -- OK

В Java/Hibernate:

@Entity
public class User {
    @Min(18)
    @Column(name = "age", columnDefinition = "INT CHECK (age >= 18)")
    private Integer age;
    
    @DecimalMin("0.00")
    @Column(columnDefinition = "DECIMAL(10,2) CHECK (balance >= 0)")
    private BigDecimal balance;
}

6. FOREIGN KEY - внешний ключ

CREATE TABLE orders (
    id BIGINT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    total DECIMAL(10, 2),
    FOREIGN KEY (user_id) REFERENCES users(id)  -- Ссылка на users
);

-- Это гарантирует:
-- - user_id должен существовать в таблице users
-- - Не можно удалить User если есть его Orders

-- Попытка вставить несуществующий user_id
INSERT INTO orders (id, user_id, total) VALUES (1, 999, 100);  -- ERROR!
-- Foreign key constraint failed

В Java/Hibernate:

@Entity
@Table(name = "orders")
public class Order {
    @Id
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false, 
                foreignKey = @ForeignKey(name = "fk_order_user"))
    private User user;  // FOREIGN KEY
}

Практический пример: полная таблица с ограничениями

CREATE TABLE users (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    email VARCHAR(255) NOT NULL UNIQUE,  -- NOT NULL + UNIQUE
    name VARCHAR(255) NOT NULL,
    age INT CHECK (age >= 18),
    phone VARCHAR(20),
    status VARCHAR(20) DEFAULT 'ACTIVE',  -- DEFAULT
    balance DECIMAL(10, 2) DEFAULT 0.00 CHECK (balance >= 0),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

CREATE TABLE orders (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    order_number VARCHAR(50) NOT NULL,
    total DECIMAL(10, 2) NOT NULL CHECK (total > 0),  -- CHECK
    status VARCHAR(20) DEFAULT 'PENDING',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    
    -- Ограничения
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    UNIQUE(user_id, order_number),  -- Уникальная комбинация
    CHECK (total > 0)
);

В Java/Hibernate:

@Entity
@Table(name = "users", uniqueConstraints = {
    @UniqueConstraint(columnNames = "email")
})
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;  // PRIMARY KEY AUTO_INCREMENT
    
    @Column(nullable = false, unique = true, length = 255)
    @Email  // Валидация
    private String email;
    
    @Column(nullable = false)
    private String name;
    
    @Min(18)
    @Column(columnDefinition = "INT CHECK (age >= 18)")
    private Integer age;
    
    @Column(length = 20)
    private String phone;
    
    @Column(length = 20, columnDefinition = "VARCHAR(20) DEFAULT 'ACTIVE'")
    private String status;
    
    @DecimalMin("0.00")
    @Column(columnDefinition = "DECIMAL(10,2) DEFAULT 0.00")
    private BigDecimal balance;
    
    @Column(nullable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private LocalDateTime createdAt;
    
    @Column(nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private LocalDateTime updatedAt;
    
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<Order> orders;
}

@Entity
@Table(name = "orders", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"user_id", "order_number"})
})
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;  // PRIMARY KEY
    
    @ManyToOne(optional = false)
    @JoinColumn(name = "user_id", nullable = false,
                foreignKey = @ForeignKey(name = "fk_order_user"))
    private User user;  // FOREIGN KEY
    
    @Column(nullable = false, length = 50)
    private String orderNumber;
    
    @DecimalMin("0.01")
    @Column(nullable = false, columnDefinition = "DECIMAL(10,2) CHECK (total > 0)")
    private BigDecimal total;  // CHECK (total > 0)
    
    @Column(length = 20, columnDefinition = "VARCHAR(20) DEFAULT 'PENDING'")
    private String status;
    
    @Column(nullable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private LocalDateTime createdAt;
}

Добавление ограничения к существующей таблице

-- Добавить PRIMARY KEY (если его нет)
ALTER TABLE users ADD PRIMARY KEY (id);

-- Добавить UNIQUE
ALTER TABLE users ADD UNIQUE (email);
-- или
ALTER TABLE users ADD CONSTRAINT uk_email UNIQUE (email);

-- Добавить NOT NULL (может быть сложно если уже есть NULL)
ALTER TABLE users MODIFY COLUMN email VARCHAR(255) NOT NULL;

-- Добавить CHECK
ALTER TABLE users ADD CONSTRAINT ck_age CHECK (age >= 18);

-- Добавить DEFAULT
ALTER TABLE users MODIFY COLUMN status VARCHAR(20) DEFAULT 'ACTIVE';

-- Добавить FOREIGN KEY
ALTER TABLE orders 
ADD CONSTRAINT fk_order_user 
FOREIGN KEY (user_id) REFERENCES users(id);

-- Удалить ограничение
ALTER TABLE users DROP CONSTRAINT uk_email;
ALTER TABLE orders DROP FOREIGN KEY fk_order_user;

Производительность ограничений

Хорошие практики:

-- ✅ БЫСТРО - индекс на поле UNIQUE
CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL  -- Автоматически индексируется
);

-- ✅ БЫСТРО - индекс на FOREIGN KEY
CREATE TABLE orders (
    user_id BIGINT,
    FOREIGN KEY (user_id) REFERENCES users(id)
);
CREATE INDEX idx_orders_user_id ON orders(user_id);

-- ❌ МЕДЛЕННО - CHECK на сложное выражение
CREATE TABLE orders (
    total DECIMAL(10, 2) 
    CHECK (total > 100 AND user_id IN (SELECT id FROM premium_users))
    -- Это проверяется при каждой вставке!
);

Важно: Каскадные действия

CREATE TABLE orders (
    id BIGINT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    
    -- При удалении User - автоматически удаляют Orders
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- Или
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
-- При удалении User - user_id = NULL

-- Или
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT
-- Не позволяет удалить User пока есть Orders

Вывод

Основные ограничения:

  • PRIMARY KEY - уникальный идентификатор
  • UNIQUE - уникальность
  • NOT NULL - обязательное значение
  • CHECK - условие на значение
  • DEFAULT - значение по умолчанию
  • FOREIGN KEY - ссылка на другую таблицу

В Java/Hibernate все это выражается через аннотации @Column, @Constraint, etc.

Как добавить ограничение для поля в таблице SQL | PrepBro