Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Khóa tổng hợp duy nhất của SQL Server của hai trường với tự động tăng trường thứ hai

Kể từ khi ai đó đăng một câu hỏi tương tự, tôi đã cân nhắc điều này. Vấn đề đầu tiên là các DB không cung cấp trình tự "có thể phân vùng" (sẽ khởi động lại / ghi nhớ dựa trên các khóa khác nhau). Thứ hai là SEQUENCE các đối tượng được cung cấp hướng đến truy cập nhanh và không thể quay lại (tức là bạn sẽ lấy khoảng trống). Về cơ bản, điều này loại trừ việc sử dụng tiện ích tích hợp sẵn ... nghĩa là chúng ta phải tự triển khai.

Điều đầu tiên chúng ta cần là một bảng để lưu trữ các số thứ tự của chúng ta. Điều này có thể khá đơn giản:

CREATE TABLE Invoice_Sequence (base CHAR(1) PRIMARY KEY CLUSTERED,
                               invoiceNumber INTEGER);

Trong thực tế, base cột phải là tham chiếu khóa ngoại cho bất kỳ bảng / id nào xác định (các) doanh nghiệp / pháp nhân mà bạn đang xuất hóa đơn. Trong bảng này, bạn muốn các mục nhập là duy nhất cho mỗi pháp nhân được cấp.

Tiếp theo, bạn muốn một proc được lưu trữ sẽ lấy một khóa (base ) và rút ra số tiếp theo trong chuỗi (invoiceNumber ). Bộ khóa cần thiết sẽ khác nhau (nghĩa là một số số hóa đơn phải có năm hoặc ngày phát hành đầy đủ), nhưng mẫu cơ sở cho trường hợp này như sau:

CREATE PROCEDURE Next_Invoice_Number @baseKey CHAR(1), 
                                     @invoiceNumber INTEGER OUTPUT 
AS MERGE INTO Invoice_Sequence Stored
              USING (VALUES (@baseKey)) Incoming(base)
                 ON Incoming.base = Stored.base
   WHEN MATCHED THEN UPDATE SET Stored.invoiceNumber = Stored.invoiceNumber + 1
   WHEN NOT MATCHED BY TARGET THEN INSERT (base) VALUES(@baseKey)
   OUTPUT INSERTED.invoiceNumber ;;

Lưu ý rằng:

  1. Bạn phải chạy điều này trong một giao dịch tuần tự
  2. Giao dịch phải giống mã đang chèn vào bảng (hóa đơn) đích.

Đúng vậy, bạn vẫn sẽ bị chặn theo từng doanh nghiệp khi phát hành số hóa đơn. Bạn không thể tránh điều này nếu các số hóa đơn phải theo thứ tự, không có khoảng trống - cho đến khi hàng thực sự được cam kết, nó có thể được cuộn lại, có nghĩa là số hóa đơn sẽ không được phát hành.

Bây giờ, vì bạn không muốn phải nhớ gọi thủ tục cho mục nhập, hãy gói nó trong một trình kích hoạt:

CREATE TRIGGER Populate_Invoice_Number ON Invoice INSTEAD OF INSERT
AS 
  DECLARE @invoiceNumber INTEGER
  BEGIN
    EXEC Next_Invoice_Number Inserted.base, @invoiceNumber OUTPUT
    INSERT INTO Invoice (base, invoiceNumber) 
                VALUES (Inserted.base, @invoiceNumber)
  END

(rõ ràng là bạn có nhiều cột hơn, bao gồm cả những cột khác sẽ được tự động điền - bạn sẽ cần điền chúng vào)
... sau đó bạn có thể sử dụng bằng cách chỉ cần nói:

INSERT INTO Invoice (base) VALUES('A');

Vậy chúng ta đã làm được những gì? Hầu hết, tất cả công việc này là về việc thu hẹp số lượng hàng bị khóa bởi một giao dịch. Cho đến khi INSERT này được cam kết, chỉ có hai hàng bị khóa:

  • Hàng trong Invoice_Sequence duy trì số thứ tự
  • Hàng trong Invoice cho hóa đơn mới.

Tất cả các hàng khác cho một base cụ thể là miễn phí - chúng có thể được cập nhật hoặc truy vấn theo ý muốn (xóa thông tin ra khỏi hệ thống kiểu này có xu hướng làm cho các kế toán viên lo lắng). Bạn có thể cần quyết định điều gì sẽ xảy ra khi các truy vấn thường bao gồm hóa đơn đang chờ xử lý ...



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách thực hiện truy vấn với group_concat trong máy chủ sql

  2. Cách kết hợp ngày từ một trường với thời gian từ một trường khác - MS SQL Server

  3. Làm cách nào để xác định trong SQL Server nếu một phạm vi dateTime chồng lên một phạm vi khác

  4. Lấy phần bên trái của chuỗi trong SQL Server (T-SQL)

  5. SQL Server:SUM () của nhiều hàng bao gồm mệnh đề where