2013-04-12 75 views
21

Tôi bị kẹt khi chuyển đổi một cột varcharUserID thành INT. Tôi biết, xin đừng hỏi tại sao cột UserID này không được tạo ra như INT ban đầu, câu chuyện dài.Máy chủ SQL: chuyển đổi varchar thành INT

Vì vậy, tôi đã thử điều này, nhưng nó không hoạt động. và đưa cho tôi một lỗi:

select CAST(userID AS int) from audit 

Lỗi:

Conversion failed when converting the varchar value '1581............................................................................................................................' to data type int.

tôi đã làm select len(userID) from audit và nó trả 128 ký tự, mà không phải là khoảng trắng.

Tôi đã cố gắng phát hiện các ký tự ASCII cho các ký tự sau số ID và giá trị ASCII = 0.

Đã cập nhật !!!

Tôi cũng đã thử LTRIM, RTRIM và thay thế char(0) bằng '', nhưng không hoạt động.

Cách duy nhất hoạt động khi tôi cho biết số ký tự cố định như sau, nhưng UserID không phải lúc nào cũng là 4 ký tự.

select CAST(LEFT(userID, 4) AS int) from audit 

Cảm ơn,

+0

Trong bảng UserID cột chỉ có giá trị nguyên hoặc giá trị Varchar bất kỳ .. Ví dụ: 122 như thế này HOẶC 122Adf như thế này ...? – Pandian

+0

cột UserID chỉ có giá trị Integer. Cảm ơn! – Milacay

Trả lời

16

Bạn có thể thử cập nhật bảng để thoát khỏi những ký tự:

UPDATE dbo.[audit] 
    SET UserID = REPLACE(UserID, CHAR(0), '') 
    WHERE CHARINDEX(CHAR(0), UserID) > 0; 

Nhưng sau đó bạn cũng sẽ cần phải sửa chữa bất cứ điều gì là đưa dữ liệu xấu này vào bảng ở nơi đầu tiên. Trong thời gian chờ đợi, có thể thử:

SELECT CONVERT(INT, REPLACE(UserID, CHAR(0), '')) 
    FROM dbo.[audit]; 

Nhưng đó không phải là giải pháp lâu dài. Sửa dữ liệu (và kiểu dữ liệu trong khi bạn đang ở đó). Nếu bạn không thể sửa chữa các kiểu dữ liệu ngay lập tức, sau đó bạn có thể nhanh chóng tìm ra thủ phạm bằng cách thêm một hạn chế kiểm tra:

ALTER TABLE dbo.[audit] 
    ADD CONSTRAINT do_not_allow_stupid_data 
    CHECK (CHARINDEX(CHAR(0), UserID) = 0); 

EDIT

Ok, do đó chắc chắn là một số nguyên 4 chữ số sau bởi sáu trường hợp CHAR (0). Và workaround tôi đăng chắc chắn làm việc cho tôi:

DECLARE @foo TABLE(UserID VARCHAR(32)); 
INSERT @foo SELECT 0x31353831000000000000; 

-- this succeeds: 
SELECT CONVERT(INT, REPLACE(UserID, CHAR(0), '')) FROM @foo; 

-- this fails: 
SELECT CONVERT(INT, UserID) FROM @foo; 

Vui lòng xác nhận rằng mã này ngày của riêng mình (tốt, là người đầu tiên SELECT, dù sao) làm việc cho bạn. Nếu nó xảy ra thì lỗi bạn đang nhận được từ một ký tự không phải là số khác trong một hàng khác (và nếu không thì có lẽ bạn có một bản dựng nơi một lỗi cụ thể chưa được sửa).Để thử và thu hẹp nó xuống, bạn có thể lấy các giá trị ngẫu nhiên từ các truy vấn sau đây và sau đó lặp qua các nhân vật:

SELECT UserID, CONVERT(VARBINARY(32), UserID) 
    FROM dbo.[audit] 
    WHERE UserID LIKE '%[^0-9]%'; 

Vì vậy, phải mất một hàng ngẫu nhiên, và sau đó dán các đầu ra vào một truy vấn như thế này:

DECLARE @x VARCHAR(32), @i INT; 
SET @x = CONVERT(VARCHAR(32), 0x...); -- paste the value here 
SET @i = 1; 
WHILE @i <= LEN(@x) 
BEGIN 
    PRINT RTRIM(@i) + ' = ' + RTRIM(ASCII(SUBSTRING(@x, @i, 1))) 
    SET @i = @i + 1; 
END 

này có thể mất một số thử và sai trước khi bạn gặp một hàng thất bại đối với một số lý do nào khác hơn CHAR(0) - vì bạn có thể không thực sự lọc ra các hàng có chứa CHAR(0) vì họ có thể chứa CHAR(0)CHAR(something else). Đối với tất cả chúng ta đều biết bạn có giá trị trong bảng như:

SELECT '15' + CHAR(9) + '23' + CHAR(0); 

... mà cũng không thể được chuyển đổi sang một số nguyên, cho dù bạn đã thay thế CHAR(0) hay không.

Tôi biết bạn không muốn nghe, nhưng tôi thực sự vui vì điều này gây đau đớn cho mọi người, bởi vì bây giờ họ có nhiều câu chuyện chiến tranh hơn để đẩy lùi khi mọi người đưa ra quyết định rất kém về loại dữ liệu.

+0

Tôi đã thử "SELECT CONVERT (INT, REPLACE (UserID, CHAR (0), '')) FROM dbo. [Audit];", nhưng nó không hoạt động. Tôi cũng đã thử LTRIM và RTRIM, nhưng không hoạt động ...Cảm ơn bạn đã giúp đỡ – Milacay

+0

@Milacay tốt, bạn có chắc 'CHAR (0)' là * chỉ * giá trị không hợp lệ trong cột không? Xin vui lòng xác định một hàng duy nhất mà điều này không thành công, và sau đó cho chúng tôi biết đầu ra của, ví dụ: 'SELECT CONVERT (VARBINARY (32), UserID) TỪ dbo. [Audit] WHERE LEFT (UserID, 4) = '1581';' –

+0

Tôi chạy truy vấn của bạn với "varbinary (32) ..." và đầu ra là: 0x31353831000000000000. BTW, trường này varchar (userID) đã được chuyển đổi từ Varbinary (128) để Varchar (128), và bây giờ tôi muốn chuyển đổi nó thành INT để tham gia với UserID trên bảng khác nhau ... Cảm ơn @Aaron – Milacay

0

tôi sẽ cố gắng triming số để xem những gì bạn nhận được:

select len(rtrim(ltrim(userid))) from audit 

nếu đó trả về giá trị đúng thì chỉ cần làm:

select convert(int, rtrim(ltrim(userid))) from audit 

nếu không trả về giá trị đúng thì Tôi sẽ thay thế để xóa không gian trống:

select convert(int, replace(userid, char(0), '')) from audit 
+0

Tôi đã thử tất cả LTRIM, RTRIM, và thay thế char (0) bằng '', nhưng cũng không hoạt động. Kỳ dị! cảm ơn. – Milacay

14

Câu hỏi này có 91.000 lượt xem có lẽ nhiều người đang tìm kiếm một giải pháp chung chung hơn về vấn đề này trong tiêu đề "lỗi khi chuyển đổi varchar để INT"

Nếu bạn đang ở trên SQL Server 2012+ một cách để xử lý dữ liệu không hợp lệ này là sử dụng TRY_CAST

SELECT TRY_CAST (userID AS INT) 
FROM audit 

trong các phiên bản trước, bạn có thể sử dụng

SELECT CASE 
     WHEN ISNUMERIC(RTRIM(userID) + '.0e0') = 1 
       AND LEN(userID) <= 11 
      THEN CAST(userID AS INT) 
     END 
FROM audit 

Cả hai trở NULL nếu giá trị không thể được đúc.

Trong trường hợp cụ thể mà bạn có trong câu hỏi của mình với các giá trị xấu đã biết, tôi sẽ sử dụng các điều sau đây.

CAST(REPLACE(userID COLLATE Latin1_General_Bin, CHAR(0),'') AS INT) 

Cố gắng thay thế ký tự null thường có vấn đề ngoại trừ nếu sử dụng đối chiếu nhị phân.

+0

Bạn vui lòng giải thích lý do tại sao thêm .0e0 làm cho nó trở thành số không? – Tigran

+1

@Tigran nó không làm cho nó số. Việc thêm điều này giúp xác nhận xem chuỗi đã là số có phải là số nguyên hay không. Ví dụ. '123' sẽ chuyển khi được viết là' 123.0e0' nhưng '123.45' sẽ thất bại vì' 123.45.0e0' không hợp lệ. –

1

Tùy chọn này dành cho ai đó Tìm kiếm kết quả, so với phiên bản gốc. Điều này làm việc cho tôi ...

declare @value varchar(max) = 'sad'; 
select sum(cast(iif(isnumeric(@value) = 1, @value, 0) as bigint)); 

returns 0 

declare @value varchar(max) = '3'; 
select sum(cast(iif(isnumeric(@value) = 1, @value, 0) as bigint)); 

returns 3 
Các vấn đề liên quan