Cách chính xác để đảm bảo các mục duy nhất trong thiết kế cơ sở dữ liệu tạm thời là gì?


10

Tôi đang gặp rắc rối với việc thiết kế cơ sở dữ liệu tạm thời. Tôi cần biết cách đảm bảo rằng tôi chỉ có một bản ghi hoạt động cho bất kỳ khung thời gian nhất định nào cho một cửa hàng. Tôi đã đọc câu trả lời này , nhưng tôi sợ rằng tôi không thể quấn đầu xung quanh việc kích hoạt sẽ hoạt động như thế nào. Đặc biệt, cách tôi sẽ làm việc kích hoạt nó vào cái hiện có của tôi để ngăn cập nhật cho các bản ghi và thay vào đó chèn một bản ghi mới. Vấn đề thực sự của tôi là tôi không biết làm thế nào để ngăn Cửa hàng có nhiều hơn một ngày hiệu lực khi ngày kết thúc là null. (tức là ngăn 2 hồ sơ hoạt động cho một cửa hàng).

Đây là những gì tôi có, nhưng nó cho phép tôi chèn một bản ghi mới cho một cửa hàng có ngày hiệu lực khác.

Bảng định nghĩa:

/****** Object:  Table [PCR].[Z_STORE_TEAM]    Script Date: 05/09/2014 13:05:57 ******/
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Z_STORE_TEAM]') AND type in (N'U'))
DROP TABLE [Z_STORE_TEAM]
GO

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Z_STORE_TEAM]') AND type in (N'U'))
BEGIN
CREATE TABLE [Z_STORE_TEAM](
    [STORENUM] [int] NOT NULL,
    [TEAM] [varchar](10) NULL,
    [EFFECTIVE] [date] NOT NULL,
    [FINISHED] [date] NULL,
PRIMARY KEY CLUSTERED 
(
    [STORENUM] ASC,
    [EFFECTIVE] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
END
GO

Dữ liệu mẫu:

INSERT [Z_STORE_TEAM] ([STORENUM], [TEAM], [EFFECTIVE], [FINISHED]) VALUES (1, N'1', CAST(0x01380B00 AS Date), CAST(0x81380B00 AS Date))
INSERT [Z_STORE_TEAM] ([STORENUM], [TEAM], [EFFECTIVE], [FINISHED]) VALUES (1, N'2', CAST(0x81380B00 AS Date), NULL)
INSERT [Z_STORE_TEAM] ([STORENUM], [TEAM], [EFFECTIVE], [FINISHED]) VALUES (2, N'1', CAST(0x01380B00 AS Date), NULL)
INSERT [Z_STORE_TEAM] ([STORENUM], [TEAM], [EFFECTIVE], [FINISHED]) VALUES (2, N'2', CAST(0x20380B00 AS Date), NULL)

Thay vì Cập nhật Kích hoạt:

CREATE TRIGGER [tr_ZStoreTeam_update] 
   ON  [Z_STORE_TEAM]
   INSTEAD OF UPDATE
AS 
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for trigger here
    INSERT INTO PCR.Z_STORE_TEAM(STORENUM,TEAM,EFFECTIVE)
    SELECT I.STORENUM,I.TEAM,GETDATE() AS EFFECTIVE
    FROM inserted I
    INNER JOIN PCR.Z_STORE_TEAM ST
        ON I.STORENUM = ST.STORENUM

    UPDATE ST
    SET FINISHED = GETDATE()
    FROM PCR.Z_STORE_TEAM ST
    INNER JOIN inserted I
        ON ST.STORENUM = I.STORENUM
        AND ST.EFFECTIVE = I.EFFECTIVE
END

GO

Câu trả lời:


13

Cách an toàn nhất để làm điều này là thực thi các quy tắc kinh doanh của bạn bằng cách sử dụng các ràng buộc toàn vẹn tham chiếu tích hợp, như Alexander Kuznetsov mô tả trong bài viết của mình, "Lưu trữ các khoảng thời gian không có sự chồng chéo" .

Áp dụng các kỹ thuật được liệt kê ở đó vào kết quả bảng mẫu của bạn trong tập lệnh sau:

CREATE TABLE [Z_STORE_TEAM](
    [STORENUM] [int] NOT NULL,
    [TEAM] [varchar](10) NULL,
    [EFFECTIVE] [date] NOT NULL,
    [FINISHED] [date] NULL,
    PRIMARY KEY CLUSTERED 
    (
        [STORENUM] ASC,
        [EFFECTIVE] ASC
    )
) ON [PRIMARY];

INSERT [Z_STORE_TEAM] 
    ([STORENUM], [TEAM], [EFFECTIVE], [FINISHED]) 
VALUES 
    (1, N'1', CAST(0x01380B00 AS Date), CAST(0x81380B00 AS Date)),
    (1, N'2', CAST(0x81380B00 AS Date), NULL),
    (2, N'1', CAST(0x01380B00 AS Date), NULL);

Sửa đổi:

-- New column to hold the previous finish date
ALTER TABLE dbo.Z_STORE_TEAM 
ADD PreviousFinished date NULL;
GO
-- Populate the previous finish date
UPDATE This
SET PreviousFinished = Previous.FINISHED
FROM dbo.Z_STORE_TEAM AS This
CROSS APPLY
(
    SELECT TOP (1) 
        Previous.FINISHED
    FROM dbo.Z_STORE_TEAM AS Previous
    WHERE 
        Previous.STORENUM = This.STORENUM
        AND Previous.FINISHED <= This.EFFECTIVE
    ORDER BY 
        Previous.FINISHED DESC
) AS Previous;
GO
ALTER TABLE dbo.Z_STORE_TEAM 
ADD CONSTRAINT UQ_STORENUM_PreviousFinished
UNIQUE (STORENUM, PreviousFinished);
GO
ALTER TABLE dbo.Z_STORE_TEAM
ADD CONSTRAINT CK_PreviousFinished_NotAfter_Effective
CHECK (PreviousFinished = EFFECTIVE);
GO
ALTER TABLE dbo.Z_STORE_TEAM
ADD CONSTRAINT UQ_STORENUM_FINISHED
UNIQUE (STORENUM, FINISHED);
GO
ALTER TABLE dbo.Z_STORE_TEAM
ADD CONSTRAINT FK_STORENUM_PreviousFinished
FOREIGN KEY (STORENUM, PreviousFinished)
REFERENCES dbo.Z_STORE_TEAM (STORENUM, FINISHED);
GO
ALTER TABLE dbo.Z_STORE_TEAM
ADD CONSTRAINT CK_EFFECTIVE_Before_FINISHED
CHECK (EFFECTIVE < FINISHED);

Nỗ lực chèn hàng thứ tư của dữ liệu mẫu hiện không thành công với thông báo lỗi:

INSERT [Z_STORE_TEAM] 
    ([STORENUM], [TEAM], [EFFECTIVE], [FINISHED]) 
VALUES 
    (2, N'2', '20140201', NULL);

Thông báo lỗi

Vui lòng đọc bài viết của Alex để hiểu cách các ràng buộc này đảm bảo dữ liệu bảng của bạn sẽ luôn hợp lệ. Có một tập hợp các ràng buộc thực thi tính toàn vẹn dữ liệu của bạn có nghĩa là không yêu cầu mã kích hoạt.

Bài viết liên quan của cùng tác giả:

Sửa đổi các khoảng thời gian tiếp giáp trong một bảng lịch sử

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.