2010-09-08 34 views
7

Hãy tưởng tượng một bảng với hàng trăm cột khác nhau trong đó. Hãy tưởng tượng, sau đó, rằng tôi có một bảng dữ liệu người dùng từ nơi tôi muốn sao chép dữ liệu vào bảng cơ sở. Vì vậy, tôi đã viết câu lệnh chèn-chọn đơn giản này và lỗi này bật lên. Vì vậy, cách thanh lịch nhất để tìm ra cột nào làm tăng lỗi?Làm thế nào để tìm ra cột nào làm tăng lỗi tràn số học khi chèn?

những suy nghĩ ban đầu của tôi về giải pháp là về gói nó trong một giao dịch mà tôi cuối cùng sẽ rollback và sử dụng một loại Divide và chinh phục cách tiếp cận:

begin tran 

insert into BaseTable (c1,c2,c3,...,cN) 
select c1,c2,c3,...,cN 
from UserTable 

rollback tran 

Và điều này rõ ràng là thất bại. Vì vậy, chúng tôi chia cột được đặt thành một nửa như sau:

begin tran 

insert into BaseTable (c1,c2,c3,...,cK) --where K = N/2 
select c1,c2,c3,...,cK --where K = N/2 
from UserTable 

rollback tran 

Và nếu không thành công thì cột bị lỗi nằm trong nửa còn lại. Và chúng tôi tiếp tục quá trình, cho đến khi chúng tôi tìm thấy cột pesky.

Mọi thứ thanh lịch hơn thế?

Lưu ý: Tôi cũng tìm thấy gần như trùng lặp với câu hỏi này nhưng nó hầu như không trả lời câu hỏi đó.

+0

Nếu bạn phù hợp với kiểu dữ liệu của UserTable với BaseTable, chèn của bạn không có bất kỳ sự cố nào. Tất cả những gì cần thiết sau đó là tìm cột * UserTable * vi phạm . –

+0

@Lieven Vâng, UserTable chỉ là ... một bảng người dùng không có hạn chế về nó, bởi vì dữ liệu trong đó là từ Excel hoặc Access hoặc không có gì. –

+0

Tôi thông cảm. Nếu đây là một cái gì đó mà cần phải được thực hiện quy định, bạn không thể tạo một kịch bản/thủ tục lưu trữ kiểm tra đầu vào của bạn? Macro và một lựa chọn đơn giản sẽ đi một chặng đường dài, giống như 'SELECT' c1 ', CAST (c1) AS INTEGER FROM UserTable'. –

Trả lời

6

kịch bản sau sẽ tạo ra SELECT báo cáo cho mỗi cột số nguyên của Basetable.
Thực hiện các câu lệnh SELECT kết quả sẽ xác định các cột vi phạm trong số Usertable của bạn.

SELECT 'PRINT ''' 
     + sc.Name 
     + '''; SELECT MIN(CAST(' 
     + sc.Name 
     + ' AS INTEGER)) FROM Usertable' 
FROM sys.columns sc 
     INNER JOIN sys.types st ON st.system_type_id = sc.system_type_id 
WHERE OBJECT_NAME(Object_ID) = 'BaseTable' 
     AND st.name = 'INT' 
+0

Chà, tôi thích cách tiếp cận này. –

-1

Rất nhiều lần phương pháp bạo lực bạn đề xuất là cách tốt nhất.

Tuy nhiên, nếu bạn có bản sao của cơ sở dữ liệu mà bạn cũng có thể đăng dữ liệu giả mạo.

chạy truy vấn trên đó để bạn không có việc chuyển mã ẩn cột đang phá vỡ nó. Đôi khi trong lỗi nó sẽ đưa ra một gợi ý như những gì là lên. Thông thường, nếu bạn đang xem xét những gì đang diễn ra, bạn có thể thấy khi nào văn bản đi vào một int hoặc ngược lại.

Tôi làm điều này và sẽ lấy đi bất kỳ thứ gì khác trong mã của tôi gây ra sự cố.

Bạn cần nhận bản sao truy vấn được tạo nơi bạn có thể sao chép và dán truy vấn vào công cụ truy vấn.

+0

Vâng, nó nói: Số học tràn trong varbinary với giá trị 1239847234.000000. Hoặc một cái gì đó để có hiệu lực. Tôi chắc chắn có thể đọc thông báo lỗi nhưng điều đó không giúp tôi bằng bất kỳ cách nào. –

+0

Vì vậy, tất cả các giá trị bạn đang kéo từ varchar và tất cả các bạn đang chèn vào varchar? bởi vì varbinary có xu hướng khiến tôi nghĩ rằng điều này không đúng. –

+0

Các cột trong BaseTable và UserTable có giống nhau không? –

-1

Tôi nghĩ bạn đang sử dụng phương pháp sai. Nếu bạn đang nhận được tràn số học bằng cách chọn các cột từ một bảng và chèn vào một bảng khác thì bạn phải chọn từ các hình lớn hơn (ví dụ: bigint) và chèn vào các cột nhỏ (ví dụ: int). Đây là điều cơ bản không chính xác để làm và bạn cần phải thay đổi cấu trúc DB của bạn để chèn các hàng từ một bảng vào bảng khác sẽ hoạt động. Kiểm tra từng cột từ mỗi bảng và xem vị trí có thể bị tràn, sau đó điều chỉnh bảng đích để dữ liệu bạn chèn sẽ phù hợp.

Tôi vẫn nghĩ rằng quan điểm của tôi là viết tắt nhưng để trả lời nhận xét của bạn nếu bạn muốn có giải pháp nhanh và bẩn. Làm cho tất cả các cột của bạn trong BaseTable varchar (MAX).

Sau đó:

insert into BaseTable (c1,c2,...,cN) 
select CAST(c1 AS varchar(max)),CAST(c2 AS varchar(max))...,cN 
from UserTable 
+2

Không, tôi không thấy bất kỳ lỗ hổng nào trong cách tiếp cận của tôi. Tôi không có quyền kiểm soát UserTable và tất cả các cột trong đó có varchar. Tôi chỉ muốn một cách nhanh chóng và bẩn thỉu để tìm ra cột nào gây ra lỗi. Nó chỉ là một tải ban đầu của dữ liệu và không nên mất rất nhiều thời gian kiểm tra này hay điều đó. Bạn có hiểu ý tôi? –

+1

Và đó không phải là trả lời câu hỏi của tôi, đó là trốn tránh nó. –

+0

Tất cả các cột là varchar? Tất cả bọn họ? –

0

Nếu đây chỉ là một cái gì đó bạn đang chạy bằng tay sau đó tùy thuộc vào bao nhiêu dữ liệu bạn đang chèn bạn có thể sử dụng mệnh đề OUTPUT để sản xuất các hàng chèn cho khách hàng.

Hàng sau lần xuất cuối cùng là hàng có vấn đề.

+0

Giả sử tôi chỉ có một hàng có nhiều cột. :) –

+0

Sau đó, bạn chỉ cần nhìn vào một hàng. – Sam

+2

@Sam, bạn đang thiếu điểm. Nó không phải là số lượng hàng có vấn đề nhưng số lượng cột. –

0

Tôi đã tiếp cận Lieven Keersmaekers 'nhưng mở rộng nó. Nếu bảng có độ dài trường số khác nhau, tập lệnh này sẽ thay đổi Cast dựa trên tên và độ chính xác của loại. Tín dụng vẫn đến Lieven vì nghĩ về giải pháp này - nó đã giúp tôi rất nhiều.

DECLARE @tableName VARCHAR(100) 

SET @tableName = 'tableName' 

SELECT 'PRINT ''' + sc.NAME + '''; SELECT MIN(CAST([' + sc.NAME + '] as ' + CASE 
     WHEN st.NAME = 'int' 
      THEN 'int' 
     ELSE st.NAME + '(' + cast(sc.precision AS VARCHAR(5)) + ',' + cast(sc.scale AS VARCHAR(5)) + ')' 
     END + ')) from ' + @tableName 
FROM sys.columns sc 
INNER JOIN sys.types st ON st.system_type_id = sc.system_type_id 
WHERE OBJECT_NAME(Object_ID) = @tableName 
    AND st.NAME NOT IN ('nvarchar', 'varchar', 'image', 'datetime', 'smalldatetime', 'char', 'nchar') 
Các vấn đề liên quan