8

Tôi đang chạy một loạt tập lệnh tạo cơ sở dữ liệu. Chúng chạy để hoàn thành trên SQL Server 2012 (11.0.5058.0). Trên SQL Server 2014 (12.0.4213.0) một lỗi kịch bản với:IsNumeric thất bại với "Một lỗi nghiêm trọng xảy ra trên lệnh hiện tại." SQL Server 2014 CTE

Msg 0, Tầng 11, Nhà nước 0, Line 0
Một lỗi nghiêm trọng xảy ra vào lệnh hiện hành. Các kết quả, nếu có, cần được loại bỏ.

Msg 0, Level 20, State 0, Line 0
Đã xảy ra lỗi nghiêm trọng trên lệnh hiện tại. Các kết quả, nếu có, cần được loại bỏ.

Dường như sử dụng kết quả của câu lệnh IsNumeric bên trong tòa nhà truy vấn ngắt truy vấn CTE, vì không có hàng nào được yêu cầu gây ra lỗi. Một phiên bản luộc xuống của trường hợp tôi chạy vào là:

CREATE TABLE #Temp1 (CTECol VARCHAR); 
CREATE TABLE #Temp2 (NumCol Int null); 
; 
WITH cte AS 
(
    SELECT 
     CASE WHEN ISNUMERIC(t.CTECol) = 1 
       THEN 1 
       ELSE null 
     END as IsNCol1 
    FROM 
     #Temp1 t 
) 
SELECT * 
FROM #Temp2 
JOIN cte ON #Temp2.NumCol = cte.IsNCol1 

Trường hợp đơn giản nhất tôi có thể tìm thấy là:

CREATE TABLE #Temp3 (CTECol Int); 
CREATE TABLE #Temp4 (NumCol Int); 
; 
WITH cte AS 
(
    SELECT ISNUMERIC(t.CTECol) as IsNCol1 
    FROM #Temp3 t 
) 
SELECT * 
FROM #Temp4 
JOIN cte ON #Temp4.NumCol = cte.IsNCol1 

Tôi đã kiểm tra mức độ lỗi từ Microsoft và có vẻ như 11 là có thể sửa chữa lỗi người dùng và 20 là lỗi nghiêm trọng nên tôi cảm thấy như tôi đang nhận được một thông điệp hỗn hợp.

Có cách nào đúng để thực hiện việc này hay là hồi quy trong năm 2014?

+0

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/7c4dd91f-4ca6-4cb9- ad8b-c8f32e9d25e7/a-nghiêm trọng-lỗi-xảy ra-on-the-current-command-the-kết quả-nếu-bất kỳ-nên-được-hủy bỏ? diễn đàn = transactsql –

+0

Kiểm tra Nhật ký lỗi SQL Server và bạn sẽ tìm thấy một ngăn xếp dump do vi phạm truy cập. Điều này cho thấy bạn đã chạy vào một lỗi hồi quy trong SQL Server 2014 (Tôi không nhận được lỗi trong SQL Server 2012 hoặc CTP SQL Server 2016 mới nhất). Lỗi nghiêm trọng 20 cấp gây tử vong thay thế lỗi nghiêm trọng 11 trước đó. –

Trả lời

2

Đây chắc chắn là lỗi.

Cũng không cần CTE tạo ra hành vi này. Bên dưới sử dụng biểu thức trực tiếp có cùng tác dụng.

SELECT * 
FROM #Temp4 
     JOIN #Temp3 
     ON #Temp4.NumCol = ISNUMERIC(#Temp3.CTECol) 

Tôi có thể repro trên 12.0.2269.0 và 12.0.4213.0 nhưng không phải 12.0.4449.0 để có vẻ như nó hiện đã được sửa.

Bài viết KB có liên quan với chi tiết là (FIX: Access violation when a query uses ISDATE or ISNUMERIC functions in Join conditions in SQL Server 2014 SP1).

Các vết đống khi ngoại lệ được ném dưới (đối với khả năng tìm kiếm)

KernelBase.dll!RaiseException() 
msvcr100.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 157 
sqldk.dll!ExceptionBackout::GetCurrentException(void) 
sqldk.dll!ex_raise2(int,int,int,int,void *,char *) 
sqldk.dll!ex_raise_va_list(int,int,int,int,char *) 
sqllang.dll!alg_ex_raise(int,int,int,int,int,...) 
sqllang.dll!CAlgTableMetadata::RaiseBadTableException(int,int) 
sqllang.dll!CAlgTableMetadata::Bind(class CRelOp_Query *,class COptExpr *) 
sqllang.dll!CRelOp_Get::BindTree(class COptExpr *,class CBindEnv *,int) 
sqllang.dll!COptExpr::BindTree(class CBindEnv *,int) 
sqllang.dll!CRelOp_FromList::BindTree(class COptExpr *,class CBindEnv *,int) 
sqllang.dll!COptExpr::BindTree(class CBindEnv *,int) 
sqllang.dll!CRelOp_QuerySpec::BindTree(class COptExpr *,class CBindEnv *,int) 
sqllang.dll!COptExpr::BindTree(class CBindEnv *,int) 
sqllang.dll!CRelOp_DerivedTable::BindTree(class COptExpr *,class CBindEnv *,int) 
sqllang.dll!COptExpr::BindTree(class CBindEnv *,int) 
sqllang.dll!CRelOp_Query::BindCTEList(class CBindEnv *,class COptExpr *) 
sqllang.dll!CRelOp_SelectQuery::BindTree(class COptExpr *,class CBindEnv *,int) 
sqllang.dll!COptExpr::BindTree(class CBindEnv *,int) 
sqllang.dll!CRelOp_Query::FAlgebrizeQuery(class COptExpr *,class CCompExecCtxtStmt const &,enum EObjType,class CSequenceProjectContext *) 
sqllang.dll!CProchdr::FNormQuery(class CCompExecCtxtStmt const &,class CAlgStmt *,enum EObjType) 
sqllang.dll!CProchdr::FNormalizeStep(class CCompExecCtxtStmt const &,class CAlgStmt *,class CCompPlan *,bool,class CParamExchange *,unsigned long *) 
sqllang.dll!CSQLSource::FCompile(class CCompExecCtxt const &,class CParamExchange *) 
sqllang.dll!CSQLSource::FCompWrapper(class CCompExecCtxt const &,class CParamExchange *,enum CSQLSource::ESqlFunction) 
sqllang.dll!CSQLSource::Transform(class CCompExecCtxt const &,class CParamExchange *,enum CSQLSource::ESqlState) 
sqllang.dll!CSQLSource::Execute(class CCompExecCtxtBasic const &,class CParamExchange *,unsigned long) 
sqllang.dll!process_request(class IBatch *,class SNI_Conn *,enum RequestType) 
sqllang.dll!process_commands(void *) 
sqldk.dll!SOS_Task::Param::Execute(class SOS_Task *,void * * const) 
sqldk.dll!SOS_Scheduler::RunTask(class Worker *) 
sqldk.dll!SOS_Scheduler::ProcessTasks(class SOS_Scheduler *,class Worker *) 
sqldk.dll!SchedulerManager::WorkerEntryPoint(class Worker *) 
sqldk.dll!SystemThread::RunWorker(class Worker *) 
sqldk.dll!SystemThreadDispatcher::ProcessWorker(class SystemThread *) 
sqldk.dll!SchedulerManager::ThreadEntryPoint(void *) 
kernel32.dll!BaseThreadInitThunk() 
ntdll.dll!RtlUserThreadStart() 
1

Tôi nghĩ đó là lỗi. Tuy nhiên, tôi đã đưa ra một cách giải quyết có thể phù hợp với bạn.

;WITH cte AS 
(
    --SELECT 
    -- CASE WHEN ISNUMERIC(t.CTECol) = 1 
    --  THEN 1 
    --  ELSE null 
    --END as IsNCol1 

    SELECT CASE WHEN TRY_PARSE(t.CTECol AS INT) IS NOT NULL 
       THEN 1 
       ELSE NULL 
      END AS IsNCol1 
    FROM #Temp1 t 
) 
SELECT * 
FROM #Temp2 
JOIN cte 
     ON #Temp2.NumCol = cte.IsNCol1 

TRY_PARSE lợi nhuận NULL nếu các diễn viên thất bại, vì vậy nếu nó là NOT NULL sau đó bạn biết đó là một int hợp lệ.

Có một số khác biệt tinh tế giữa hai chức năng, nhưng tôi thích TRY_PARSE anyway, bởi vì theo MSDN

lợi nhuận IsNumeric 1 đối với một số nhân vật mà không phải là con số, chẳng hạn như cộng (+), trừ (-), và các ký hiệu tiền tệ hợp lệ như dấu đô la ($)

UPDATE:

Tôi có lẽ nên làm rõ một trong những khác biệt tinh tế.ISNUMERIC lợi nhuận 1 nếu tham số có thể được phân tích để bất kỳ kiểu số, và họ là:

  • int
  • số
  • bigint
  • tiền
  • smallint
  • smallmoney
  • tinyint
  • float
  • thập phân
  • thực

Nó không phải là giống như TRY_PARSE, mà cố gắng để phân tích các đầu vào cho một trong những cụ kiểu dữ liệu trên. (Trong ví dụ của tôi, nó INT). Vì vậy, nếu bạn thực sự muốn bắt chước ISNUMERIC, bạn sẽ cần phải sử dụng một lồng nhau (hoặc phẳng) CASE cho mỗi loại. Ngay cả khi đó hành vi vẫn có thể hơi bất ngờ, nhưng đó là một câu chuyện hoàn toàn khác.

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