Xuất bản thay đổi cơ sở dữ liệu với SSDT bao gồm thay đổi loại dữ liệu của cột


9

Tôi có một dự án Công cụ dữ liệu SQL Server (VS2012) được xuất bản tự động trong quá trình xây dựng. Một cột gần đây đã được cập nhật từ một intđến decimal(18,4). Do thay đổi này, việc xuất bản không thành công với lỗi

(49,1): SQL72014: .Net SqlClient Nhà cung cấp dữ liệu: Msg 50000, Cấp 16, Trạng thái 127, Dòng 6 đã được phát hiện. Cập nhật lược đồ đang chấm dứt vì mất dữ liệu có thể xảy ra. (44,0): SQL72045: Lỗi thực thi tập lệnh. Tập lệnh được thực thi: / * Loại cho cột Số lượng Được nhận trong bảng [dbo]. Mất dữ liệu có thể xảy ra. * /

NẾU EXISTS (chọn top 1 1 từ [dbo]. [Reconcestion_Receiving]) RAISERROR (N'Rows đã được phát hiện. Cập nhật lược đồ đang chấm dứt vì mất dữ liệu có thể xảy ra. ', 16, 127) VỚI NGAY BÂY GIỜ bị xử tử.

Tôi hiểu lý do tại sao tôi nhận được lỗi đó và tôi biết rằng nó có thể được giải quyết bằng cách vô hiệu hóa cờ "Chặn triển khai tăng dần nếu mất dữ liệu có thể xảy ra". Tuy nhiên, có sự phản đối rất mạnh mẽ đối với việc vô hiệu hóa tính năng đó, vì vậy đây sẽ không phải là một giải pháp chấp nhận được.

Giải pháp khác duy nhất tôi có thể nghĩ đến là làm như sau:

  1. Tạo một bảng tạm thời và sao chép nội dung của bảng hiện có vào bảng tạm thời
  2. Cắt bớt bảng hiện có
  3. Hãy để SSDT cập nhật kiểu dữ liệu
  4. Điền lại dữ liệu từ bảng tạm thời

Điều đó có vẻ khủng khiếp và không hiệu quả, mặc dù.

Có một lựa chọn tốt hơn?


2
Tham khảo: Quản lý chuyển động dữ liệu trong quá trình triển khai của bạn (Phần 1) ( blog.msdn.com/b/bahill/archive/2009/03/30/ ám ). Nó bao gồm tất cả các điểm mà @ MarkStorey-Smith đã mô tả với các ví dụ.
Kin Shah

Xem xét sử dụng mặc định thông minh thay vì ... http://sqlblog.com/blogs/jamie_thomson/archive/2012/05/31/smart-defaults-ssdt.aspx
NAADEV

Câu trả lời:


4

Tôi cũng đã cố gắng bỏ qua lá cờ đó nhưng đã đứng về phía đồng nghiệp của bạn và bây giờ cố gắng giải quyết những vấn đề này một cách "chính xác". Lộ trình ít ỏi hơn (bên lề) là sử dụng các tập lệnh triển khai trước và sau để thực hiện công việc đổi tên.

  • Đổi tên bảng hiện có trong một kịch bản trước khi triển khai.
  • Với bảng hiện có bị thiếu, bảng trong tiêu điểm sẽ được tạo theo định nghĩa lược đồ mới.
  • Trong một kịch bản hậu triển khai, sao chép từ bảng gốc đã đổi tên thành phiên bản mới.

Tùy thuộc vào bản chất của mục tiêu, tất nhiên bạn có thể cần phải quan tâm đến việc bỏ và tạo lại các ràng buộc khóa ngoại.


Với "bản sao từ" bạn có nghĩa là sao chép hồ sơ? Và nếu bạn đổi tên nó, bạn sẽ chỉ có 1 bảng, làm thế nào cái cũ vẫn còn đó? Bạn có nghĩa là tạo một bảng mới với cùng cấu trúc?
MrFox

@MrFox Tôi sẽ thêm một ví dụ trong vài ngày tới.
Mark Storey-Smith

2

Trong trường hợp của tôi, tôi đã loại bỏ một cột khỏi bảng.

Giải pháp được cung cấp trong câu trả lời này không hiệu quả với tôi, nó đã gây ra invalid object namelỗi trong quá trình xuất bản.

Tôi thấy rằng cần phải sao chép các hàng từ bảng, vô hiệu hóa kiểm tra ràng buộc và xóa các hàng trong tập lệnh triển khai trước, sau đó sao chép các hàng trở lại vào bảng với chức năng chèn nhận dạng được kích hoạt trong tập lệnh triển khai bài.

Trong Script.PreDeployment.sql:

-- copy and delete dbo.Table1
BEGIN TRY
    IF (EXISTS (
        SELECT * FROM INFORMATION_SCHEMA.TABLES 
        WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'Table1_copy'))
    BEGIN
        PRINT 'Dropping Table1_copy'
        DROP TABLE dbo.Table1_copy
    END

    PRINT 'Copying dbo.Table1'

    SELECT @LastID = MAX(ID), @StartID = MIN(ID)
    FROM dbo.Table1

    SET @EndID = @StartID + 1000

    SELECT * 
    INTO dbo.Table1_copy 
    FROM dbo.Table1
    WHERE ID BETWEEN @StartID AND @EndId

    SET @StartID = @EndID + 1

    SET IDENTITY_INSERT dbo.Table1_copy ON

    WHILE @StartID < @LastID
    BEGIN
        SET @EndID = @StartID + 1000

        INSERT dbo.Table1_copy (ID, Column1, Column2, Column3)
        SELECT ID, Column1, Column2, Column3
        FROM dbo.Table1
        WHERE ID BETWEEN @StartID AND @EndId

        SET @StartID = @EndID + 1
    END

    SET IDENTITY_INSERT dbo.Table1_copy OFF

    PRINT 'Copied dbo.Table1 to dbo.Table1_copy'

    EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"

    PRINT 'Deleting dbo.Table1'
    WHILE EXISTS (SELECT 1 FROM dbo.Table1) 
        DELETE TOP(1000) FROM dbo.Table1
    PRINT 'Deleted dbo.Table1'

    PRINT 'SUCCESS: Copy and delete dbo.Table1'
END TRY
BEGIN CATCH
    EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"

    PRINT 'ERROR: Copy and delete dbo.Table1'
    PRINT 'ERROR MESSAGE: ' + ERROR_MESSAGE()
END CATCH
GO

Trong Script.PostDeployment.sql

DECLARE @StartID BIGINT, @LastID BIGINT, @EndID BIGINT

-- populate dbo.Table1
BEGIN TRY
    PRINT 'Populating dbo.Table1'

    SET IDENTITY_INSERT dbo.Table1 ON

    SELECT @LastID = MAX(ID)
    FROM dbo.Table1_copy

    WHILE @StartID < @LastID
    BEGIN
        SET @EndID = @StartID + 1000

        INSERT dbo.Table1 (ID, Column1, Column2, Column3)
        SELECT ID, Column1, Column2, Column3
        FROM dbo.Table1
        WHERE ID BETWEEN @StartID AND @EndId

        SET @StartID = @EndID + 1
    END

    SET IDENTITY_INSERT dbo.Table1 OFF

    EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"

    PRINT 'SUCCESS: Populating dbo.Table1'
END TRY
BEGIN CATCH
    SET IDENTITY_INSERT dbo.Table1 OFF

    PRINT 'ERROR: Populating dbo.Table1'
    PRINT 'ERROR MESSAGE: ' + ERROR_MESSAGE()
END CATCH
GO
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.