2016-02-11 36 views
11

Tôi muốn thực hiện phép tính số học dựa trên các giá trị cột của tôi. Hãy xem xét ví dụ sau quảSố học/Thao tác logic dựa trên giá trị Cột

CREATE TABLE #test 
    (
    cont_sal INT, 
    check_value INT, 
    operator VARCHAR(50) 
) 

INSERT #test 
VALUES (10,20,'+'), 
     (20,10,'+'), 
     (10,20,'-'), 
     (20,10,'-') 

dự kiến:

cont_sal check_value result 
-------- ----------- ------ 
10   20   30 
20   10   30 
10   20   -10 
20   10   10 

tôi có thể làm bằng CASE tuyên bố này.

SELECT cont_sal, 
     check_value, 
     CASE 
     WHEN operator = '+' THEN cont_sal + check_value 
     when operator = '-' THEN cont_sal - check_value 
     END result 
FROM #test 

Nhưng có cách nào để thực hiện điều này một cách linh hoạt hay không. Nhà điều hành có thể là bất cứ điều gì như /, %, *. Một cái gì đó như thế này

DECLARE @sql NVARCHAR(max)='' 

SET @sql = 'select cont_sal ' + 'operator' 
      + ' check_value from #test ' 

--PRINT @sql 

EXEC Sp_executesql 
    @sql 

Mà rõ ràng đã không làm việc nói

Msg 102, Level 15, State 1, Line 1 cú pháp sai gần 'check_value'.

+4

Sử dụng các biểu CASE' '. Nó sẽ là đơn giản nhất để giải thích. –

+3

Bạn có nghĩa là 'SET @sql = 'chọn cont_sal' + @op + 'check_value từ #test'' .. – Deepshikha

+2

@Mini - Mỗi hàng sẽ có toán tử riêng vì vậy chúng tôi không thể sử dụng biến –

Trả lời

5

Câu hỏi hay.

Tôi sẽ sử dụng một biểu thức trường hợp vì:

  1. Chỉ có five arithmetic operators.
  2. Bạn không thể trực tiếp đại diện cho toán tử số học.
  3. Bạn không thể thực thi nội dòng động SQL.

Nhưng có các lựa chọn thay thế. Bạn có thể xây dựng và sau đó thực hiện một câu lệnh SQL động.

-- Query will be stored here. 
DECLARE @Qry VARCHAR(255) = ''; 

-- Build up the query. 
SELECT 
    @Qry = 
     @Qry 
     + CASE ROW_NUMBER() OVER (ORDER BY cont_sal) 
       WHEN 1 THEN 'SELECT ' 
       ELSE 'UNION ALL SELECT ' 
      END 
     + '''' 
     + Expression 
     + '''' 
     + ' AS Expression,' 
     + Expression 
     + ' AS Result ' 
FROM 
    #test AS t 
     CROSS APPLY 
      (
       -- Avoid typing expression twice. 
       SELECT 
        CAST(cont_sal AS VARCHAR(50)) 
         + ' ' 
         + operator 
         + ' ' 
         + CAST(check_value AS VARCHAR(50)) AS Expression   
      ) AS ex 
; 

-- Execute it. 
EXECUTE(@Qry); 

Hoặc bạn có thể sử dụng dấu thập chéo áp dụng để tính kết quả sử dụng vũ lực.

SELECT 
    *  
FROM 
    #test AS t 

     CROSS APPLY 
      (
       VALUES 
        ('+', cont_sal + check_value), 
        ('-', cont_sal - check_value), 
        ('*', cont_sal * check_value), 
        ('/', cont_sal/NULLIF(check_value, 0)), 
        ('%', cont_sal % NULLIF(check_value, 0)) 
      ) AS ex(operator, result) 
WHERE 
    ex.operator = t.operator 
; 

Ở đây mọi hoạt động có thể được tính toán. Những thứ không bắt buộc được lọc ra khỏi tập kết quả. Cách tiếp cận này dễ đọc và viết hơn, nhưng chạy các phép tính không bao giờ được yêu cầu. Điều đó nói rằng, nó đã tạo ra một kế hoạch truy vấn nhanh hơn mà ví dụ động của tôi.

EDIT

Nhờ @Damien_The_Unbeliever, người đã chỉ ra lỗ hổng của tôi để chia cho số không lỗi. Tôi đã sử dụng NULLIF để hoán đổi số 0 cho giá trị rỗng, tránh lỗi.

Tôi chỉ cập nhật ví dụ thứ 2.

+2

Ví dụ cuối cùng - có nguy cơ một phân chia bằng 0 lỗi ở đây nếu 'check_value' là 0, ngay cả đối với các hàng mà' toán tử' không phân chia, vì hệ thống có thể quyết định chạy tất cả các phép tính. –

+0

Tôi biết tôi sẽ không thoát khỏi điều này! Tốt, tôi sẽ chỉnh sửa. –

+0

Phương thức 'Áp dụng chéo 'đã sử dụng :) –

1

Disclaimer: Tôi là chủ sở hữu của dự án Eval SQL.NET

Thư viện này cho phép sử dụng cú pháp C# trực tiếp trong T-SQL để đánh giá biểu hiện động số học. Ưu tiên toán tử và dấu ngoặc đơn được tôn trọng và thư viện đi xa hơn biểu thức toán học đơn giản.

CREATE TABLE #test 
    (
     cont_sal INT , 
     check_value INT , 
     operator VARCHAR(50) 
    ) 

INSERT #test 
VALUES (10, 20, '+'), 
     (20, 10, '+'), 
     (10, 20, '-'), 
     (20, 10, '-') 

DECLARE @sqlnet SQLNET = SQLNET::New('') 

SELECT cont_sal , 
     check_value , 
     @sqlnet.Code('x ' + operator + ' y') 
      .Val('x', cont_sal) 
      .Val('y', check_value) 
      .Eval() 
FROM #test 

DROP TABLE #test 

Tài liệu: SQL Server Eval - Dynamically evaluate arithmetic operation and expression

+0

Cảm ơn bạn. Sẽ kiểm tra xem nó ra –

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