2017-08-07 2 views
1

ich auf eine Anfrage arbeite, die ich brauche Wert basierend auf einer anderen SpalteSQL Query Spalte als Formel zu verwenden Wert zu berechnen

Im Folgenden angegeben berechnet auf Formel ist meine Tabelle:

enter image description here

Ich muss die Abfrage schreiben, um Wert zu erhalten, der auf FORMULA Spalte basiert. zB I führen müssen als

enter image description here

Als Formel könnte alles sein aus meinen Spalten PRICE und SIZE, wie schreibe ich die Abfrage dies zu erreichen?

+4

Es gibt keine einfache Möglichkeit, dies zu tun. Ein Ansatz würde einen Cursor und dynamisches SQL verwenden. –

+0

Warum setzen Sie den Wert während der Aktualisierung nicht auf die berechnete Spalte in der Tabelle? Wenn Update geschieht nicht in SQL – ASpirin

+0

Auch in SQL kann z. B. onupdate Trigger dynamische SQL ausführen, um Wert zu berechnen und in die Spalte – ASpirin

Antwort

1

Eine andere Alternative, die relativ einfach zu machen ist, ist eine CLR. Sie können die Berechnungsmethode von DataTable verwenden, um einen einfachen einzeiligen Code in C# anzugeben.

[Microsoft.SqlServer.Server.SqlFunction] 
public static double Evaluate(SqlString expression) 
{ 
    return double.Parse((new DataTable()).Compute(expression.ToString(), "").ToString()); 
} 

Dann die Montage zu SQL Server hinzufügen und die Wrapper-Funktion erstellen:

CREATE FUNCTION [dbo].[Evaluate](@expression [nvarchar](4000)) 
RETURNS [float] WITH EXECUTE AS CALLER 
AS 
EXTERNAL NAME [YourAssemblyName].[YourClassName].[Evaluate] 
GO 

Jetzt können Sie die Funktion im Rahmen einer einfachen SELECT-Anweisung aufrufen:

SELECT itemid, price, size, formula, 
dbo.Evaluate(REPLACE(REPLACE(formula, 'PRICE', FORMAT(price,'0.00')), 
'SIZE', FORMAT(size, '0'))) as calcvalue FROM YourTable 
+0

Lösung für mich gearbeitet .. noch nicht sicher über die Leistung – Rohaan

+0

Ich bin froh, geholfen zu haben. Meiner Erfahrung nach sind die CLR-Funktionen sehr schnell, aber ich musste noch nie einen auf einem Tisch mit mehr als 60-70.000 Datensätzen verwenden, daher möchte ich nicht gerne sagen, was die schnellste Lösung ist. Ich fürchte, ich bin sehr viel von der Schule "repariere nicht, was nicht kaputt ist". Wenn ich eine Lösung finde, die für mich funktioniert, suche ich nicht nach einem anderen :-) –

0

vorausgesetzt, die Formel, die Sie brauchen in einer Spalte zB durch einen Wert ab, um zu verwenden: Größe, die Sie, wenn ein Fall verwenden könnte die (einzige) Weg zu gehen und es ist nicht so kompliziert

select price, size, when size= 2 then (price*1.2)/size 
      when size= 3 then price/size 
      end my_calc 
    from my_table 
+0

meine Formel könnte alles andere als die angegebene sein. – Rohaan

+0

Sie haben ein Kriterium für die Formel? Dann können Sie Ihre Kriterien klassifizieren ..und wie vorgeschlagen vorgehen. Andernfalls können Sie Ihre Formel speichern (sql-konform) und den Code mit dinamic sql zuweisen. – scaisEdge

+0

Es gibt keine spezifischen Kriterien. – Rohaan

2

Dynamische Abfrage ist:

DECLARE @query NVARCHAR(MAX) = ''; 

SELECT @query = @query + ' 
UNION 
SELECT ItemID, Price, Size, Formula, ' + Formula + ' AS CalcValue FROM YourTable WHERE Formula = ''' + Formula + ''' ' 
FROM YourTable; 
SET @query = STUFF(@query,1,8,''); 

PRINT @query; 

EXEC (@query); 

SQLFiddle DEMO

Aber Sie müssen sich bewusst sein, wie fehleranfällig ist dies. Wenn der Wert der Formelspalte nicht gültig ist, bricht die Formelabfrage ab.

bearbeiten: mit UNION statt UNION ALL wegen derselben Formel in mehreren Reihen erscheinen, geht

edit2: Plan B - Statt Bündel gleicher SELECT-Abfragen ausführen und unterschiedliche Ergebnisse zu machen, besser zu machen verschiedene Formeln zu Beginn:

DECLARE @query NVARCHAR(MAX) = ''; 

WITH CTE_DistinctFormulas AS 
(
    SELECT DISTINCT Formula FROM YourTable 
) 
SELECT @query = @query + ' 
UNION ALL 
SELECT ItemID, Price, Size, Formula, ' + Formula + ' AS CalcValue FROM YourTable WHERE Formula = ''' + Formula + ''' ' 
FROM CTE_DistinctFormulas; 
SET @query = STUFF(@query,1,12,''); 

PRINT @query; 

EXEC (@query); 

SQLFiddle DEMO 2 - added few more rows

0

Ich habe etwas Ähnliches und wenn Sie in einem kleineren Pool von Operationen spielen, ist es nicht so schwer. Ich ging mit einer Serie, in der ich X- und Y-Säulen und einen Operator hatte. Dann habe ich gerade einen großen Fall gemacht, als ich eine Aussage über die Identifizierung des Operators und die darauf basierende Logik getroffen habe. Möglicherweise müssen Sie Ihre Struktur etwas ändern. Der Kern des Problems besteht darin, dass SQL eine Ergebnismengen-basierte Engine ist. Alles, was Sie tun müssen, um eine Operation zu bestimmen, wird langsamer sein.Beispiel:

DECLARE @Formula TABLE 
(
    FormulaId INT IDENTITY 
, FormulaName VARCHAR(128) 
, Operator VARCHAR(4) 
); 

DECLARE @Values TABLE 
( 
    ValueId INT IDENTITY 
, FormulaId INT 
, Price MONEY 
, Size INT 
) 

INSERT INTO @Formula (FormulaName, Operator) 
VALUES ('Simple Addition', '+'), ('Simple Subtraction', '-'), ('Simple Multiplication', '*'), ('Simple Division', '/'), ('Squared', '^2'), ('Grow by 20 percent then Multiply', '20%*') 

INSERT INTO @Values (FormulaId, Price, Size) 
VALUES (1, 10, 5),(2, 10, 5),(3, 10, 5),(4, 10, 5),(5, 10, 5),(6, 10, 5),(1, 16, 12),(6, 124, 254); 

Select * 
From @Values 

SELECT 
    f.FormulaId 
, f.FormulaName 
, v.ValueId 
, Price 
, Operator 
, Size 
, CASE WHEN Operator = '+' THEN Price + Size 
     WHEN Operator = '-' THEN Price - Size 
     WHEN Operator = '*' THEN Price * Size 
     WHEN Operator = '/' THEN Price/Size 
     WHEN Operator = '^2' THEN Price * Price 
     WHEN OPerator = '20%*' THEN (Price * 1.20) * Size 
     END AS Output 
FROM @Values v 
    INNER JOIN @Formula f ON f.FormulaId = v.FormulaId 

Mit dieser Methode ist mein Betrieb wirklich nur ein Zeiger Verweis auf eine andere Tabelle, die einen Operator, der nur ein Zeichen Ich für meinen Fall Anweisung für alle Absichten und Zwecke ist wirklich hat. Sie können das sogar potentiell zusammensetzen und wenn Sie mehrere übergeben wollten, könnten Sie eine 'Gruppen' Spalte und eine 'Sequenz' hinzufügen und nacheinander tun. Es hängt davon ab, wie schwierig Ihre "Formeln" werden. Wenn Sie in mehr als 3 oder 4 Variablen kommen, die sich häufig mit häufigen Operatoränderungen ändern, dann würden Sie wahrscheinlich dynamische SQL machen wollen. Aber wenn es nur ein paar Dinge sind, sollte das nicht so schwer sein. Bedenken Sie jedoch, dass der Nachteil dieses Ansatzes darin besteht, dass er auf einer bestimmten Ebene fest codiert ist, aber flexibel ist, dass die Parameter, die in ihn eingegeben werden, diese Formel immer wieder anwenden können.

Verwandte Themen