← Назад к вопросам
Как добавить ограничение для поля в таблице 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.