2016-05-25 3 views
2

Ich bin mir ziemlich sicher, dass die Antwort Nein ist, aber ich möchte es überprüfen. Wenn es einen Weg gibt, müssen Sie es nicht wirklich programmieren, ein Vorschlag für eine Methode könnte helfen. Ich habe 1 große Auswahl mit Unterabfrage versucht, etc., aber ich kann nicht herausfinden, wie man es bekommt, um den richtigen Datensatz auszuwählen.Ist es möglich, eine Inline-Tabellenwertfunktion aus dieser Skalarfunktion zu erstellen?

Die Tabelle muss sich selbst wieder verbinden, um inverse Beziehungen zu erhalten. Der folgende Code ist nur ein Testbeispiel.

Danke

create function [dbo].[fnUOMFactor_Inline] (
     @ItemID  nvarchar(20) 
,  @FromUnit nvarchar(10) 
,  @ToUnit  nvarchar(10) 
    ) 

returns numeric(28,12) 
as 
begin 

declare @Factor  numeric(28,12) 


if  @FromUnit = @ToUnit 
set  @Factor = 1 

--  Simple 1-step 
if  @Factor is null 
select @Factor = factor 
from dbo.UnitConvertTest 
WHere itemid = @ItemID 
and  fromunit = @FromUnit 
and  tounit = @ToUnit 


--  Inverted 1-step 
if  @Factor is null 
select @Factor = 1/factor 
from dbo.UnitConvertTest 
Where itemid = @ItemID 
and  fromunit = @ToUnit 
and  tounit = @FromUnit 


if  @Factor is null 
select @Factor = uc1.factor * uc2.factor 
from dbo.UnitConvertTest uc1 
join dbo.UnitConvertTest uc2 on uc1.itemid = uc2.itemid 
          and uc1.tounit = uc2.fromunit 

where uc1.itemid = @ItemID 
and  uc1.fromunit = @FromUnit 
and  uc2.tounit = @ToUnit 
and  uc1.factor <> 0 
and  uc2.factor <> 0 

--  Inverted 2-step 
if  @Factor is null 
select @Factor = 1/(uc1.factor * uc2.factor) 
from dbo.UnitConvertTest uc1 
join dbo.UnitConvertTest uc2  on uc1.itemid = uc2.itemid 
           and uc1.tounit = uc2.fromunit 
Where uc1.itemid = @ItemID 
and  uc1.fromunit = @ToUnit 
and  uc2.tounit = @FromUnit 

--  Complex 2-step (same fromunit) 
if  @Factor is null 
select @Factor = uc1.factor/uc2.factor 
from dbo.UnitConvertTest uc1 
join dbo.UnitConvertTest uc2 on uc1.itemid = uc2.itemid 
          and uc1.fromunit = uc2.fromunit 
Where uc1.itemid = @ItemID 
and  uc1.tounit = @ToUnit 
and  uc2.tounit = @FromUnit 


--  Complex 2-step (same tounit) 
if  @Factor is null 
select @Factor = uc1.factor/uc2.factor 
from dbo.UnitConvertTest uc1 
join dbo.UnitConvertTest uc2 on uc1.itemid = uc2.itemid 
          and uc1.tounit = uc2.tounit 
Where uc1.itemid = @ItemID 
and  uc1.fromunit = @FromUnit 
and  uc2.fromunit = @ToUnit 

--  Default 
if  @Factor is null 
set  @Factor = 1 

return @Factor 
end 

Dies ist eine Tabelle mit ein paar Datensätze zum Testen.

CREATE TABLE [dbo].[UnitConvertTest](
[FROMUNIT] [nvarchar](10) NOT NULL, 
[TOUNIT] [nvarchar](10) NOT NULL, 
[FACTOR] [numeric](28,12) NOT NULL, 
[ITEMID] [nvarchar](20) NOT NULL, 
) ON [PRIMARY] 

insert into dbo.UnitConvertTest (FROMUNIT, TOUNIT, FACTOR, ITEMID) 

Values ('CT','PT','40.00','TEST') 
,  ('RM','CT','10.00','TEST') 
,  ('RM','PT','400.00','TEST') 


Select [dbo].[fnUOMFactor_Inline] ('Test','PT','RM') 

Antwort

1

Jede schleifenfreie Skalarfunktion kann durch mechanische Transformationen in einen Inline-TVP umgewandelt werden. Die Transformationen können jedoch zu einer großen Abfrage führen.

Ihr Code scheint eine Kette von Fallback-Berechnungen zu sein. Sie können es wie folgt schreiben:

select FinalResult = coalesce(x.factor, f1.fallback, f2.fallback, f3.fallback, ...) 
from (values (convert(decimal(28, 12, null))) x(factor) 
cross apply (select fallback = {computeFallback1}) f1 
cross apply (select fallback = {computeFallback2}) f2 
cross apply (select fallback = {computeFallback3}) f3 
... 

Im Wesentlichen diese Modelle eine Reihe von Skalarberechnungen durch eine einzeilige Tabelle, die wir kontinuierlich Spalten hinzufügen zu ...

Dies in einer Abfrage mit der Leistung führen können Probleme. Es wird wahrscheinlich Schleifenverbindungen erzwingen.

+0

Genie, danke! Bisher konnte ich die Funktion damit in eine Inline-Version umschreiben und mein Testbeispiel funktioniert einwandfrei. Ich habe es durch einige größere Datensätze geführt und es schien zu funktionieren und eine Leistungsverbesserung zu sein. Ich habe es dann durch einen noch größeren Datensatz geführt, und ich habe den Fehler unten erhalten. Ich bin nicht sicher, wie das möglich ist, basierend auf der Struktur der Funktion. Irgendeine Idee? Fehler: Unterabfrage gab mehr als 1 Wert zurück. Dies ist nicht zulässig, wenn die Unterabfrage =,! =, <, <= , >,> = oder wenn die Unterabfrage als Ausdruck verwendet wird. –

+0

Ich denke, ich sehe, wo das Problem sein könnte. In Ihrem Beispiel habe ich die Unterabfrage in {computefallback}. Irgendwo erfülle ich die Kriterien, um 2 Reihen zu ergeben. Ich denke, die alte Funktion verhält sich in diesen Szenarien wie ein "Update" und wählt nur den ersten Wert aus. Vielleicht kann ich ein MAX() hinzufügen, um einen Faktor auszuwählen, wie es die existierende Logik tut. –

+0

Der alte Code hatte dann einen Fehler. Es wurde ein nicht-deterministischer Wert gewählt ... Richtig, du kannst MAX oder TOP 1 ORDER BY verwenden. – usr

Verwandte Themen