2016-02-11 13 views
11

Ich möchte arithmetische Operation basierend auf meinen Spaltenwerten durchführen. Betrachten Sie das folgende BeispielArithmetische/logische Operation basiert auf Spaltenwert

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

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

Erwartetes Ergebnis:

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

ich dies mit CASE Aussage machen kann.

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

Aber gibt es eine Möglichkeit, dies dynamisch zu tun. Betreiber kann alles wie /, %, * sein. So etwas wie dies

DECLARE @sql NVARCHAR(max)='' 

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

--PRINT @sql 

EXEC Sp_executesql 
    @sql 

die offensichtlich nicht

Msg 102, Ebene 15, Status 1, Zeile 1 Falsche Syntax in der Nähe von 'check_value' sagen funktionierten.

+4

Mit dem 'CASE' Ausdruck. Es wird am einfachsten sein, darüber nachzudenken. –

+3

Sie meinen 'SET @sql = 'wählen cont_sal' + @op + 'check_value von #test'' .. – Deepshikha

+2

@Mini - Jede Zeile wird einen eigenen Operator haben, so dass wir keine Variable verwenden können –

Antwort

5

Große Frage.

würde ich einen Fall Ausdruck verwenden, weil:

  1. Es gibt nur five arithmetic operators sind.
  2. Sie können arithmetische Operatoren nicht direkt parametrieren.
  3. Sie können dynamisches SQL nicht inline ausführen.

Aber es gibt Alternativen. Sie könnten eine dynamische SQL-Anweisung erstellen und dann ausführen.

-- 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); 

Oder Sie könnten ein Kreuz verwenden, um das Ergebnis mit Brute-Force zu berechnen.

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 
; 

Hier wird jeder mögliche Vorgang berechnet. Diejenigen, die nicht benötigt werden, werden aus der Ergebnismenge herausgefiltert. Dieser Ansatz ist einfacher zu lesen und zu schreiben, führt jedoch Berechnungen aus, die niemals erforderlich sind. Allerdings hat es einen schnelleren Abfrageplan als mein dynamisches Beispiel generiert.

EDIT

Dank @Damien_The_Unbeliever, der meine Verwundbarkeit durch Null-Fehler zu teilen hingewiesen. Ich habe NULLIF verwendet, um 0s gegen Nullen auszutauschen, was den Fehler vermeidet.

Ich habe nur das 2. Beispiel aktualisiert.

+2

Letztes Beispiel - es besteht ein Risiko von ein Fehler durch Division durch Null, wenn "check_value" gleich 0 ist, sogar für Zeilen, bei denen "operator" nicht dividiert ist, da das System möglicherweise entscheidet, alle Berechnungen auszuführen. –

+0

Ich wusste, dass ich damit nicht durchkommen würde! Guter Punkt, ich werde bearbeiten. –

+0

Verwendet Cross Apply Methode :) –

1

Disclaimer: Ich bin der Eigentümer des Projekts Eval SQL.NET

Diese Bibliothek ermöglicht C# Syntax direkt in T-SQL verwenden dynamisch arithmetischen Ausdruck zu bewerten. Operator Vorrang und Klammern werden geehrt und die Bibliothek geht weit über den einfachen mathematischen Ausdruck hinaus.

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 

Dokumentation: SQL Server Eval - Dynamically evaluate arithmetic operation and expression

+0

Vielen Dank. Wird es überprüfen –