Загрузка данных
-- Дополнение существующей схемы гостиницы.
-- Сначала сделайте резервную копию базы user305_db.
-- Старые таблицы и записи гостей/броней не удаляются.
USE [user305_db];
GO
IF OBJECT_ID(N'dbo.RoomType25', N'U') IS NULL OR
OBJECT_ID(N'dbo.Room25', N'U') IS NULL OR
OBJECT_ID(N'dbo.Guest25', N'U') IS NULL OR
OBJECT_ID(N'dbo.Booking25', N'U') IS NULL OR
OBJECT_ID(N'dbo.Service25', N'U') IS NULL OR
OBJECT_ID(N'dbo.BookingService25', N'U') IS NULL OR
OBJECT_ID(N'dbo.Payment25', N'U') IS NULL
THROW 51000, N'Не найдена одна из семи исходных таблиц в dbo. Проверьте базу данных.', 1;
GO
-- 1. Скидки
IF OBJECT_ID(N'dbo.Discount25', N'U') IS NULL
BEGIN
CREATE TABLE dbo.Discount25 (
ID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Discount25 PRIMARY KEY,
Title nvarchar(80) NOT NULL,
[Percent] decimal(5,2) NOT NULL,
ClientCategory nvarchar(80) NOT NULL,
Conditions nvarchar(300) NULL,
IsActive bit NOT NULL CONSTRAINT DF_Discount25_IsActive DEFAULT (1),
CONSTRAINT UQ_Discount25_Title UNIQUE (Title),
CONSTRAINT CK_Discount25_Percent CHECK ([Percent] > 0 AND [Percent] <= 100)
);
END;
GO
IF COL_LENGTH(N'dbo.Booking25', N'DiscountID') IS NULL
ALTER TABLE dbo.Booking25 ADD DiscountID int NULL;
GO
IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys
WHERE name = N'FK_Booking25_Discount25'
AND parent_object_id = OBJECT_ID(N'dbo.Booking25'))
ALTER TABLE dbo.Booking25 WITH CHECK
ADD CONSTRAINT FK_Booking25_Discount25 FOREIGN KEY (DiscountID)
REFERENCES dbo.Discount25(ID);
GO
-- 2. Сотрудники
IF OBJECT_ID(N'dbo.Employee25', N'U') IS NULL
BEGIN
CREATE TABLE dbo.Employee25 (
ID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Employee25 PRIMARY KEY,
FirstName nvarchar(50) NOT NULL,
LastName nvarchar(50) NOT NULL,
Patronymic nvarchar(50) NULL,
[Position] nvarchar(80) NOT NULL,
[Floor] int NULL,
PersonnelNumber nvarchar(20) NOT NULL,
Phone nvarchar(30) NULL,
IsActive bit NOT NULL CONSTRAINT DF_Employee25_IsActive DEFAULT (1),
CONSTRAINT UQ_Employee25_PersonnelNumber UNIQUE (PersonnelNumber),
CONSTRAINT CK_Employee25_Floor CHECK ([Floor] IS NULL OR [Floor] > 0)
);
END;
GO
-- Заявка на услугу одновременно служит заданием сотруднику
IF COL_LENGTH(N'dbo.BookingService25', N'Status') IS NULL
ALTER TABLE dbo.BookingService25
ADD [Status] nvarchar(30) NOT NULL
CONSTRAINT DF_BookingService25_Status DEFAULT (N'Ожидает') WITH VALUES;
GO
IF COL_LENGTH(N'dbo.BookingService25', N'EmployeeID') IS NULL
ALTER TABLE dbo.BookingService25 ADD EmployeeID int NULL;
GO
IF COL_LENGTH(N'dbo.BookingService25', N'CompletedAt') IS NULL
ALTER TABLE dbo.BookingService25 ADD CompletedAt datetime2(0) NULL;
GO
IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys
WHERE name = N'FK_BookingService25_Employee25'
AND parent_object_id = OBJECT_ID(N'dbo.BookingService25'))
ALTER TABLE dbo.BookingService25 WITH CHECK
ADD CONSTRAINT FK_BookingService25_Employee25 FOREIGN KEY (EmployeeID)
REFERENCES dbo.Employee25(ID);
GO
-- 3. Учётные записи для будущих входа и регистрации
-- Хеш и соль будут вычисляться в приложении; пароли текстом в БД не записываются
IF OBJECT_ID(N'dbo.UserAccount25', N'U') IS NULL
BEGIN
CREATE TABLE dbo.UserAccount25 (
ID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_UserAccount25 PRIMARY KEY,
[Login] nvarchar(100) NOT NULL,
PasswordHash varbinary(32) NOT NULL,
PasswordSalt varbinary(16) NOT NULL,
PasswordAlgorithm nvarchar(30) NOT NULL
CONSTRAINT DF_UserAccount25_Algorithm DEFAULT (N'PBKDF2-SHA256'),
PasswordIterations int NOT NULL,
[Role] nvarchar(30) NOT NULL,
GuestID int NULL,
EmployeeID int NULL,
IsActive bit NOT NULL CONSTRAINT DF_UserAccount25_IsActive DEFAULT (1),
CreatedAt datetime2(0) NOT NULL CONSTRAINT DF_UserAccount25_CreatedAt DEFAULT (SYSUTCDATETIME()),
LastLoginAt datetime2(0) NULL,
CONSTRAINT UQ_UserAccount25_Login UNIQUE ([Login]),
CONSTRAINT FK_UserAccount25_Guest25 FOREIGN KEY (GuestID) REFERENCES dbo.Guest25(ID),
CONSTRAINT FK_UserAccount25_Employee25 FOREIGN KEY (EmployeeID) REFERENCES dbo.Employee25(ID),
CONSTRAINT CK_UserAccount25_Algorithm CHECK (PasswordAlgorithm = N'PBKDF2-SHA256'),
CONSTRAINT CK_UserAccount25_Iterations CHECK (PasswordIterations >= 600000),
CONSTRAINT CK_UserAccount25_RoleLink CHECK (
([Role] = N'Клиент' AND GuestID IS NOT NULL AND EmployeeID IS NULL) OR
([Role] IN (N'Сотрудник', N'Администратор') AND EmployeeID IS NOT NULL AND GuestID IS NULL)
)
);
END;
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes
WHERE object_id = OBJECT_ID(N'dbo.UserAccount25')
AND name = N'UX_UserAccount25_GuestID')
CREATE UNIQUE INDEX UX_UserAccount25_GuestID
ON dbo.UserAccount25(GuestID) WHERE GuestID IS NOT NULL;
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes
WHERE object_id = OBJECT_ID(N'dbo.UserAccount25')
AND name = N'UX_UserAccount25_EmployeeID')
CREATE UNIQUE INDEX UX_UserAccount25_EmployeeID
ON dbo.UserAccount25(EmployeeID) WHERE EmployeeID IS NOT NULL;
GO
-- 4. Расписание смен
IF OBJECT_ID(N'dbo.Shift25', N'U') IS NULL
BEGIN
CREATE TABLE dbo.Shift25 (
ID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Shift25 PRIMARY KEY,
EmployeeID int NOT NULL,
ShiftDate date NOT NULL,
StartTime time(0) NOT NULL,
EndTime time(0) NOT NULL,
[Floor] int NULL,
Note nvarchar(200) NULL,
CONSTRAINT FK_Shift25_Employee25 FOREIGN KEY (EmployeeID) REFERENCES dbo.Employee25(ID),
CONSTRAINT UQ_Shift25_EmployeeDateStart UNIQUE (EmployeeID, ShiftDate, StartTime)
);
END;
GO
-- 5. Журнал уборок
IF OBJECT_ID(N'dbo.Cleaning25', N'U') IS NULL
BEGIN
CREATE TABLE dbo.Cleaning25 (
ID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Cleaning25 PRIMARY KEY,
RoomID int NOT NULL,
EmployeeID int NULL,
CleaningDate date NOT NULL,
[Status] nvarchar(30) NOT NULL,
Comment nvarchar(300) NULL,
StartedAt datetime2(0) NULL,
CompletedAt datetime2(0) NULL,
CONSTRAINT FK_Cleaning25_Room25 FOREIGN KEY (RoomID) REFERENCES dbo.Room25(ID),
CONSTRAINT FK_Cleaning25_Employee25 FOREIGN KEY (EmployeeID) REFERENCES dbo.Employee25(ID)
);
END;
GO
-- 6. Сообщения администратору
IF OBJECT_ID(N'dbo.Message25', N'U') IS NULL
BEGIN
CREATE TABLE dbo.Message25 (
ID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Message25 PRIMARY KEY,
EmployeeID int NOT NULL,
Subject nvarchar(120) NOT NULL,
Body nvarchar(1000) NOT NULL,
SentAt datetime2(0) NOT NULL CONSTRAINT DF_Message25_SentAt DEFAULT (SYSUTCDATETIME()),
[Status] nvarchar(30) NOT NULL CONSTRAINT DF_Message25_Status DEFAULT (N'Новое'),
CONSTRAINT FK_Message25_Employee25 FOREIGN KEY (EmployeeID) REFERENCES dbo.Employee25(ID)
);
END;
GO
-- 7. Реквизиты гостиницы
IF OBJECT_ID(N'dbo.HotelSettings25', N'U') IS NULL
BEGIN
CREATE TABLE dbo.HotelSettings25 (
ID int NOT NULL CONSTRAINT PK_HotelSettings25 PRIMARY KEY,
HotelName nvarchar(150) NOT NULL,
[Address] nvarchar(250) NULL,
Phone nvarchar(30) NULL,
Email nvarchar(100) NULL,
UpdatedAt datetime2(0) NOT NULL CONSTRAINT DF_HotelSettings25_UpdatedAt DEFAULT (SYSUTCDATETIME()),
CONSTRAINT CK_HotelSettings25_SingleRow CHECK (ID = 1)
);
END;
GO
-- Учебные записи на русском. Существующие строки не перезаписываются
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
INSERT dbo.Discount25 (Title, [Percent], ClientCategory, Conditions, IsActive)
SELECT v.Title, v.[Percent], v.ClientCategory, v.Conditions, 1
FROM (VALUES
(N'Постоянный гость', CAST(10.00 AS decimal(5,2)), N'Постоянный клиент', N'После трёх завершённых бронирований'),
(N'Пенсионная', CAST(7.00 AS decimal(5,2)), N'Пенсионер', N'При предъявлении подтверждающего документа'),
(N'Корпоративная', CAST(15.00 AS decimal(5,2)), N'Корпоративный клиент', N'По договору с организацией')
) AS v(Title, [Percent], ClientCategory, Conditions)
WHERE NOT EXISTS (SELECT 1 FROM dbo.Discount25 d WHERE d.Title = v.Title);
INSERT dbo.Employee25
(FirstName, LastName, Patronymic, [Position], [Floor], PersonnelNumber, Phone, IsActive)
SELECT v.FirstName, v.LastName, v.Patronymic, v.[Position],
v.[Floor], v.PersonnelNumber, v.Phone, 1
FROM (VALUES
(N'Анна', N'Соколова', N'Игоревна', N'Администратор',
NULL, N'А-001', N'+7 (000) 000-00-01'),
(N'Мария', N'Иванова', N'Сергеевна', N'Горничная',
1, N'С-001', N'+7 (000) 000-00-02'),
(N'Дмитрий', N'Петров', N'Алексеевич', N'Сотрудник ресторана',
2, N'С-002', N'+7 (000) 000-00-03')
) AS v(FirstName, LastName, Patronymic, [Position],
[Floor], PersonnelNumber, Phone)
WHERE NOT EXISTS (
SELECT 1 FROM dbo.Employee25 e
WHERE e.PersonnelNumber = v.PersonnelNumber
);
IF NOT EXISTS (SELECT 1 FROM dbo.HotelSettings25 WHERE ID = 1)
INSERT dbo.HotelSettings25
(ID, HotelName, [Address], Phone, Email)
VALUES
(1, N'Гостиница «Айзатулин»',
N'г. Ярославль, ул. Учебная, д. 1',
N'+7 (000) 000-00-00', N'info@example.test');
INSERT dbo.Shift25
(EmployeeID, ShiftDate, StartTime, EndTime, [Floor], Note)
SELECT e.ID, CONVERT(date, v.DayText, 112),
CONVERT(time(0), v.StartText),
CONVERT(time(0), v.EndText),
v.[Floor], v.Note
FROM (VALUES
(N'С-001', N'20260930', N'08:00', N'16:00', 1, N'Утренняя смена'),
(N'С-001', N'20261001', N'08:00', N'16:00', 1, N'Утренняя смена'),
(N'С-002', N'20260930', N'12:00', N'20:00', 2, N'Дневная смена')
) AS v(PersonnelNumber, DayText, StartText, EndText, [Floor], Note)
INNER JOIN dbo.Employee25 e
ON e.PersonnelNumber = v.PersonnelNumber
WHERE NOT EXISTS (
SELECT 1 FROM dbo.Shift25 s
WHERE s.EmployeeID = e.ID
AND s.ShiftDate = CONVERT(date, v.DayText, 112)
AND s.StartTime = CONVERT(time(0), v.StartText)
);
-- Уборки появятся только если в Room25 уже есть номера
INSERT dbo.Cleaning25
(RoomID, EmployeeID, CleaningDate, [Status], Comment)
SELECT TOP (2)
r.ID, e.ID, CONVERT(date, '20260930', 112),
N'Запланирована', N'Проверить номер и сменить бельё'
FROM (
SELECT TOP (2) ID, RoomNumber
FROM dbo.Room25
ORDER BY RoomNumber, ID
) r
INNER JOIN dbo.Employee25 e
ON e.PersonnelNumber = N'С-001'
WHERE NOT EXISTS (
SELECT 1 FROM dbo.Cleaning25 c
WHERE c.RoomID = r.ID
AND c.CleaningDate = CONVERT(date, '20260930', 112)
)
ORDER BY r.RoomNumber;
INSERT dbo.Message25 (EmployeeID, Subject, Body, [Status])
SELECT e.ID, v.Subject, v.Body, N'Новое'
FROM (VALUES
(N'С-001', N'Нужны чистые полотенца',
N'Для номеров первого этажа требуется пополнить запас полотенец.'),
(N'С-002', N'Заявка на обслуживание',
N'Прошу проверить наличие дополнительных услуг для гостей второго этажа.')
) AS v(PersonnelNumber, Subject, Body)
INNER JOIN dbo.Employee25 e
ON e.PersonnelNumber = v.PersonnelNumber
WHERE NOT EXISTS (
SELECT 1 FROM dbo.Message25 m
WHERE m.EmployeeID = e.ID
AND m.Subject = v.Subject
);
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
THROW;
END CATCH;
GO
-- Проверка количества записей
SELECT N'Discount25' AS TableName, COUNT(*) AS RowsCount
FROM dbo.Discount25
UNION ALL SELECT N'Employee25', COUNT(*) FROM dbo.Employee25
UNION ALL SELECT N'UserAccount25', COUNT(*) FROM dbo.UserAccount25
UNION ALL SELECT N'Shift25', COUNT(*) FROM dbo.Shift25
UNION ALL SELECT N'Cleaning25', COUNT(*) FROM dbo.Cleaning25
UNION ALL SELECT N'Message25', COUNT(*) FROM dbo.Message25
UNION ALL SELECT N'HotelSettings25', COUNT(*) FROM dbo.HotelSettings25;