Azure Data Warehouse - Benutzerdefinierte Funktionsprobleme

7

Hat hier jemand Glück gehabt, UDFs in der Azure Data Warehouse- Datenbank zu erstellen und zu verwenden ? Ich bin gerade dabei, ein On-Prem-Warehouse von SQL Server 2014 auf Azure Datawarehouse zu migrieren, und bin auf ein Problem mit UDFs gestoßen.

CREATE FUNCTION dbo.fn_GetImpliedRate (@Multiple float, @term int)
RETURNS float
AS
BEGIN
    DECLARE @ImpInt float
    IF(@Term = 1)
        SET @ImpInt = (select [1] from  dbo.ImpliedRate where Multiple = @Multiple); 
    IF(@Term = 2)
        SET @ImpInt = (select [2] from  dbo.ImpliedRate where Multiple = @Multiple); 
    IF(@Term = 3)
        SET @ImpInt = (select [3] from  dbo.ImpliedRate where Multiple = @Multiple); 
    IF(@Term = 4)
        SET @ImpInt = (select [4] from  dbo.ImpliedRate where Multiple = @Multiple); 

RETURN @ImpInt

END;
GO

Diese UDF funktioniert perfekt unter SQL Server 2014. Wenn ich sie in Azure Data Warehouse erstelle, wird sie erstellt, funktioniert aber nicht, wenn ich sie abfrage. Es gibt a zurück NULL. Ich habe offensichtliche Dinge überprüft, wie ob die Zieltabelle existiert usw. Alle überprüfen. Ich habe mir die Dokumentation zu CREATE FUNCTION für Azure Data Warehouse angesehen und sie enthält eine Beispiel-UDF, die intin eine konvertiert wird decimal. Dies funktioniert in Azure DW einwandfrei. In dem Moment, in dem ich eine einfache Funktion schreibe, die eine hat select, schlägt sie fehl. Leider ist die Dokumentation von Azure hier nicht wirklich hilfreich, und ich habe mich gefragt, ob einer von Ihnen auf dieses Problem gestoßen ist. Wenn ja, wie haben Sie das gelöst?

Ich habe gerade einen anderen Anwendungsfall getestet und es funktioniert auch nicht:

CREATE function [dbo].[fn_GetNumberBusinessDays] 
(
    @StartDate datetime,
    @EndDate Datetime
)
returns int
as 
begin 

DECLARE @NDAYS INT = 0
SELECT @NDAYS = 
  ISNULL( (DATEDIFF(dd, @StartDate, @EndDate) + 1)
  -(DATEDIFF(wk, @StartDate, @EndDate) * 2)
  -(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
  -(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END) - 1 ,0) + 1


 SELECT @NDAYS = @NDAYS - COUNT(*)
 FROM dbo.FedHolidays
 WHERE DateOfHoliday BETWEEN @StartDate AND @EndDate


 RETURN @NDAYS
end
GO
RK Kuppala
quelle

Antworten:

6

Funktionen in Azure DW unterstützen keine Select-Anweisungen, die wie in Ihrem Anwendungsfall auf Tabellen zugreifen (siehe CREATE FUNCTION (SQL Data Warehouse)) :

function_body
Gibt an, dass eine Reihe von Transact-SQL-Anweisungen, die nicht auf Datenbankdaten (Tabellen oder Ansichten) verweisen, den Wert der Funktion definieren.

Könnten Sie überprüfen, ob die Funktion in DW erstellt wurde?

Jovan MSFT
quelle
6

Azure SQL Data Warehouse unterstützt UDFs nur eingeschränkt. Die Syntax wird noch nicht unterstützt SELECT @var =. Stattdessen müssen Sie DECLARE @var int =oder verwenden SET @var =. SQL DW-UDFs unterstützen auch noch keine Abfragen für Benutzertabellen. Bitte nutzen Sie unsere Feedback-Seite , um für neue Funktionen zu stimmen.

Sonya Marshall
quelle
8
"Unsere" Feedback-Seite! Arbeiten Sie für Microsoft? Es wäre schön, wenn Sie Ihre Zugehörigkeit hier oder in Ihrem Profil erklären würden.
Michael Green
Danke @sony. Die Dokumentationsseite war diesbezüglich nicht spezifisch und ich begann mit der Migration eines Warehouse für einen Client, der verspricht, dass das Azure-Warehouse im Vergleich zu etwas wie Rotverschiebung nur minimale Änderungen erfordert. Wenn Sie von Microsoft stammen, schlage ich Änderungen an der Dokumentation vor, um diese Dinge explizit zu machen.
RK Kuppala
2

Für Azure SQL Data Warehouse gibt es ein Data Warehouse-Migrationsdienstprogramm ( hier verfügbar ), das Probleme wie inkompatible Datentypen, Inline-Funktionen, Verwendung von Hinweisen, Verwendung von RETURNAnweisungen INSERT ... EXECund viele andere aufgreift:

Beispiel für einen Datenbankkompatibilitätsbericht

Leider nimmt es keine skalaren Funktionen auf, die auf Tabellen verweisen, und das sollte es auch. Für Ihre spezielle Funktion kann es sich jedoch nur um eine Ansicht (oder sogar eine andere Tabelle) handeln, z

CREATE VIEW dbo.vw_ImpliedRates
AS
SELECT 1 term, [1] impliedRate, Multiple
FROM  dbo.ImpliedRate 
UNION ALL
SELECT 2 term, [2], Multiple
FROM  dbo.ImpliedRate 
UNION ALL
SELECT 3 term, [3], Multiple
FROM  dbo.ImpliedRate 
UNION ALL
SELECT 4 term, [4], Multiple
FROM  dbo.ImpliedRate;
GO

CREATE TABLE dbo.test
(
    Multiple    FLOAT NOT NULL,
    Term        INT NOT NULL
);
GO

INSERT INTO dbo.test ( Multiple, Term )
VALUES
    ( 0.001, 1 ), ( 0.001, 2 ), ( 0.001, 3 ), ( 0.001, 4 );
GO


SELECT impliedRate, v.Multiple
FROM dbo.test t
    INNER JOIN dbo.vw_ImpliedRates v
        ON t.Multiple = v.Multiple
       AND t.Term = v.Term;

SELECT *
FROM dbo.vw_ImpliedRates
WHERE Multiple = 0.001
  AND Term = 2

Ich habe dies in meinem Azure SQL Data Warehouse versucht und es hat einwandfrei funktioniert.

Sie sollten auch wissen, dass Skalarfunktionen in SQL Server nicht gut skaliert werden können, wenn sie für Tabellen aufgerufen werden. Wenn Sie über das für Azure SQL Data Warehouse geeignete Volume (dh Milliarden von Zeilen) verfügen, müssen Sie die Verwendung von Skalarfunktionen überdenken wie auch immer. Das Verwenden CTASund Schreiben von mehr prozeduralem Code ist beispielsweise ein guter Ansatz, mit dem Sie diese immens leistungsstarke Plattform ordnungsgemäß nutzen können.

wBob
quelle