Tôi muốn lưu trữ một hàng trong bảng cấu hình cho ứng dụng của mình. Tôi muốn thực thi rằng bảng này chỉ có thể chứa một hàng.
Cách đơn giản nhất để thực thi ràng buộc hàng đơn là gì?
Tôi muốn lưu trữ một hàng trong bảng cấu hình cho ứng dụng của mình. Tôi muốn thực thi rằng bảng này chỉ có thể chứa một hàng.
Cách đơn giản nhất để thực thi ràng buộc hàng đơn là gì?
Name
?
ar
nhận xét của s. Vấn đề là, nếu bạn chỉ lưu trữ các cặp tên / giá trị, thì giá trị khá tốt phải là chuỗi và bạn không có cách nào để thực thi xác thực trong cơ sở dữ liệu. Khi bạn sử dụng bảng một hàng với các cột riêng biệt cho từng cài đặt (như OP muốn) thì bạn có thể dễ dàng thực thi xác thực cho từng cài đặt cấu hình thông qua các ràng buộc kiểm tra.
Câu trả lời:
Bạn đảm bảo rằng một trong các cột chỉ có thể chứa một giá trị, sau đó đặt đó làm khóa chính (hoặc áp dụng ràng buộc duy nhất).
CREATE TABLE T1(
Lock char(1) not null,
/* Other columns */,
constraint PK_T1 PRIMARY KEY (Lock),
constraint CK_T1_Locked CHECK (Lock='X')
)
Tôi có một số bảng này trong các cơ sở dữ liệu khác nhau, chủ yếu để lưu trữ cấu hình. Tốt hơn rất nhiều khi biết rằng, nếu mục cấu hình phải là một int, bạn sẽ chỉ đọc một int từ DB.
comp.databases.theory
, một nhóm usenet (hiển thị thông qua các nhóm Google) mà tôi thừa nhận rằng tôi đã không đọc nhiều gần đây. Nó thiên về lý thuyết quan hệ hơn là SQL - nhưng tôi tình cờ biết rằng dportas / sqlvogel cũng thường xuyên lui tới cùng một nhóm. TTM là một tham chiếu đến Tuyên ngôn thứ ba , đây là một cuốn sách hay nói (một lần nữa) về lý thuyết quan hệ hơn là SQL.
Tôi thường sử dụng cách tiếp cận của Damien, cách này luôn mang lại hiệu quả tốt cho tôi, nhưng tôi cũng nói thêm một điều:
CREATE TABLE T1(
Lock char(1) not null DEFAULT 'X',
/* Other columns */,
constraint PK_T1 PRIMARY KEY (Lock),
constraint CK_T1_Locked CHECK (Lock='X')
)
Thêm "DEFAULT 'X'", bạn sẽ không bao giờ phải đối phó với cột Khóa và sẽ không phải nhớ đâu là giá trị khóa khi tải bảng lần đầu tiên.
Lock char(1) not null CONSTRAINT DF_T1_Lock DEFAULT 'X'
Bạn có thể muốn suy nghĩ lại về chiến lược này. Trong các tình huống tương tự, tôi thường thấy việc để các hàng cấu hình cũ nằm xung quanh để tìm thông tin lịch sử là vô giá.
Để làm điều đó, bạn thực sự có thêm một cột creation_date_time
(ngày / giờ chèn hoặc cập nhật) và một trình kích hoạt chèn hoặc chèn / cập nhật sẽ điền chính xác vào ngày / giờ hiện tại.
Sau đó, để có được cấu hình hiện tại của bạn, bạn sử dụng một số thứ như:
select * from config_table order by creation_date_time desc fetch first row only
(tùy thuộc vào hương vị DBMS của bạn).
Bằng cách đó, bạn vẫn có thể duy trì lịch sử cho các mục đích khôi phục (bạn có thể bắt đầu quy trình dọn dẹp nếu bảng quá lớn nhưng điều này khó xảy ra) và bạn vẫn có thể làm việc với cấu hình mới nhất.
SELECT TOP 1 ... ORDER BY creation_date_time DESC
Bạn có thể triển khai một kích hoạt INSTEAD OF để thực thi loại logic nghiệp vụ này trong cơ sở dữ liệu.
Trình kích hoạt có thể chứa logic để kiểm tra xem bản ghi đã tồn tại trong bảng chưa và nếu có, hãy QUAY LẠI Chèn.
Bây giờ, quay lại một bước để nhìn vào bức tranh lớn hơn, tôi tự hỏi liệu có cách nào thay thế và phù hợp hơn để bạn lưu trữ thông tin này, có lẽ trong một tệp cấu hình hoặc biến môi trường chẳng hạn?
Tôi sử dụng một trường bit cho khóa chính với tên IsActive. Vì vậy, có thể có tối đa 2 hàng và và sql để lấy hàng hợp lệ là: chọn * từ Cài đặt trong đó IsActive = 1 nếu bảng có tên Cài đặt.
Đây là một giải pháp mà tôi đã đưa ra cho một bảng kiểu khóa chỉ có thể chứa một hàng, giữ Y hoặc N (ví dụ: trạng thái khóa ứng dụng).
Tạo bảng với một cột. Tôi đặt một ràng buộc kiểm tra trên một cột để chỉ có thể đặt một Y hoặc N vào đó. (Hoặc 1 hoặc 0, hoặc bất cứ điều gì)
Chèn một hàng trong bảng, với trạng thái "bình thường" (ví dụ: N nghĩa là không bị khóa)
Sau đó, tạo một kích hoạt INSERT trên bảng chỉ có SIGNAL (DB2) hoặc RAISERROR (SQL Server) hoặc RAISE_APPLICATION_ERROR (Oracle). Điều này làm cho mã ứng dụng có thể cập nhật bảng, nhưng bất kỳ INSERT nào không thành công.
Ví dụ về DB2:
create table PRICE_LIST_LOCK
(
LOCKED_YN char(1) not null
constraint PRICE_LIST_LOCK_YN_CK check (LOCKED_YN in ('Y', 'N') )
);
--- do this insert when creating the table
insert into PRICE_LIST_LOCK
values ('N');
--- once there is one row in the table, create this trigger
CREATE TRIGGER ONLY_ONE_ROW_IN_PRICE_LIST_LOCK
NO CASCADE
BEFORE INSERT ON PRICE_LIST_LOCK
FOR EACH ROW
SIGNAL SQLSTATE '81000' -- arbitrary user-defined value
SET MESSAGE_TEXT='Only one row is allowed in this table';
Làm việc cho tôi.
Câu hỏi cũ nhưng làm thế nào về việc sử dụng IDENTITY (MAX, 1) của một loại cột nhỏ?
CREATE TABLE [dbo].[Config](
[ID] [tinyint] IDENTITY(255,1) NOT NULL,
[Config1] [nvarchar](max) NOT NULL,
[Config2] [nvarchar](max) NOT NULL
IF NOT EXISTS ( select * from table )
BEGIN
///Your insert statement
END
Ở đây chúng ta cũng có thể tạo một giá trị ẩn sẽ giống nhau sau lần nhập đầu tiên trong cơ sở dữ liệu. Ví dụ: Bảng Sinh viên: Id: int firstname: char Ở đây trong hộp nhập, chúng ta phải chỉ định cùng một giá trị cho cột id sẽ hạn chế như sau lần nhập đầu tiên khác với việc viết khóa bla bla do hạn chế về khóa chính nên mãi mãi chỉ có một hàng. Hi vọng điêu nay co ich!
(Name, Value)
có khóa chính trên Tên. Sau đó, bạn có thểselect Value from Table where Name = ?
chắc chắn rằng không có hàng hoặc một hàng sẽ được trả lại.