Aracılığıyla paylaş


Kullanıcı tanımlı işlevler oluşturma (Veritabanı Altyapısı)

Şunlar için geçerlidir:SQL ServerAzure SQL VeritabanıAzure SQL Yönetilen ÖrneğiAzure Synapse AnalyticsAnalytics Platform Sistemi (PDW)Microsoft Fabric'te SQL Veritabanı

Bu makalede, Transact-SQL kullanarak SQL Server'da kullanıcı tanımlı bir işlevin (UDF) nasıl oluşturulacağı açıklanır.

Sınırlamalar

Kullanıcı tanımlı işlevler, veritabanı durumunu değiştiren eylemler gerçekleştirmek için kullanılamaz.

Kullanıcı tanımlı işlevler, hedef olarak tablo içeren bir OUTPUT INTO yan tümcesi içeremez.

Kullanıcı tanımlı işlevler birden çok sonuç kümesi döndüremez. Birden çok sonuç kümesi döndürmeniz gerekiyorsa kayıtlı prosedür kullanın.

Kullanıcı tanımlı bir işlevde hata işleme kısıtlandı. UDF, TRY...CATCH, @ERROR veya RAISERROR'yi desteklemez.

Kullanıcı tanımlı işlevler saklı yordamı çağıramaz, ancak genişletilmiş saklı yordamı çağırabilir.

Kullanıcı tanımlı işlevler dinamik SQL veya geçici tablolardan yararlanamaz. Tablo değişkenlerine izin verilir.

SET deyimlerine kullanıcı tanımlı bir işlevde izin verilmez (örneğin, SET NOCOUNT ON;). Değişken değeri atamak için SET kullanılabilir.

FOR XML yan tümcesine izin verilmez.

İç içe kullanıcı tanımlı işlevler

Kullanıcı tanımlı işlevler iç içe yerleştirilmiş olabilir. Başka bir ifadeyle, kullanıcı tanımlı bir işlev başka bir işlev çağırabilir. Çağrılan işlev yürütmeyi başlattığında iç içe geçme düzeyi artırılır ve çağrılan işlev yürütmeyi bitirdiğinde iç içe geçme düzeyi azaltılır.

Kullanıcı tanımlı işlevler en fazla 32 düzey iç içe yerleştirilebilir. İç içe yerleştirme düzeylerinin üst sınırının aşılması, çağıran işlev zincirinin tamamının başarısız olmasına neden olur. Transact-SQL kullanıcı tanımlı işlevden yönetilen koda yapılan tüm başvurular, 32 düzeyli iç içe geçme sınırına karşı bir düzey olarak sayılır.

Yönetilen kodun içinden çağrılan yöntemler bu sınıra karşı sayılmaz.

Service Broker ifadeleri

Aşağıdaki Hizmet Aracısı deyimleri Transact-SQL kullanıcı tanımlı işlevin tanımına eklenemez:

  • BEGIN DIALOG CONVERSATION
  • END CONVERSATION
  • GET CONVERSATION GROUP
  • MOVE CONVERSATION
  • RECEIVE
  • SEND

Yan etki işlevleri

Aşağıdaki belirsiz yerleşik işlevler Transact-SQL kullanıcı tanımlı bir işlevde (UDF) kullanılamaz .

  • NEWID
  • NEWSEQUENTIALID
  • RAND
  • TEXTPTR

UDF içinde bu işlevlerden birine başvurursanız aşağıdaki hatayı alırsınız:

Msg 443, Level 16, State 1
Invalid use of a side-effecting operator <operator> within a function.

Belirleyici ve belirsiz yerleşik sistem işlevlerinin listesi için bkz. Deterministic ve nondeterministic functions.

Bu sorunu çözmek için, yan etki yaratan işlevi bir görünüme sarmalayabilir ve bir işlev içerisinde görünümü çağırabilirsiniz.

İzinler

Veritabanında CREATE FUNCTION izni ve işlevin oluşturulduğu şema üzerinde ALTER izni gerektirir. İşlev kullanıcı tanımlı bir tür belirtiyorsa, tür üzerinde EXECUTE izni gerektirir.

Skaler işlev örnekleri

Skaler işlev (skaler UDF)

Aşağıdaki örnek, AdventureWorks2025 veritabanında çoklu ifadeli bir skaler fonksiyon (skaler UDF ) oluşturur. İşlev bir giriş değeri, bir ProductIDalır ve envanterde belirtilen ürünün toplam miktarı olan tek bir veri değeri döndürür.

IF OBJECT_ID(N'dbo.ufnGetInventoryStock', N'FN') IS NOT NULL
    DROP FUNCTION ufnGetInventoryStock;
GO

CREATE FUNCTION dbo.ufnGetInventoryStock (@ProductID INT)
RETURNS INT
AS
-- Returns the stock level for the product.
BEGIN
    DECLARE @ret AS INT;
    SELECT @ret = SUM(p.Quantity)
    FROM Production.ProductInventory AS p
    WHERE p.ProductID = @ProductID
          AND p.LocationID = '6';
    IF (@ret IS NULL)
        SET @ret = 0;
    RETURN @ret;
END

Aşağıdaki örnek, 75 ile 80 arasında ufnGetInventoryStock olan ürünlerin geçerli stok miktarını döndürmek için ProductModelID işlevini kullanır.

SELECT ProductModelID,
       Name,
       dbo.ufnGetInventoryStock(ProductID) AS CurrentSupply
FROM Production.Product
WHERE ProductModelID BETWEEN 75 AND 80;

Skaler işlevler hakkında daha fazla bilgi ve örnek için bkz. CREATE FUNCTION .

Tablo değerli işlev örnekleri

Doğrudan tablo değerli fonksiyon (TVF)

Aşağıdaki örnek, AdventureWorks2025 veritabanında satır içi tablo değerli bir fonksiyon (TVF) oluşturur. İşlev, bir giriş parametresi olarak müşteri (mağaza) kimliği alır ve mağazada satılan her bir ürün için ProductID, Nameve yılın başından bugüne kadar olan satışların toplamını YTD Total olarak geri döndürür.

IF OBJECT_ID(N'Sales.ufn_SalesByStore', N'IF') IS NOT NULL
    DROP FUNCTION Sales.ufn_SalesByStore;
GO

CREATE FUNCTION Sales.ufn_SalesByStore (@storeid INT)
RETURNS TABLE
AS
RETURN
(
    SELECT P.ProductID,
            P.Name,
            SUM(SD.LineTotal) AS 'Total'
     FROM Production.Product AS P
          INNER JOIN Sales.SalesOrderDetail AS SD
              ON SD.ProductID = P.ProductID
          INNER JOIN Sales.SalesOrderHeader AS SH
              ON SH.SalesOrderID = SD.SalesOrderID
          INNER JOIN Sales.Customer AS C
              ON SH.CustomerID = C.CustomerID
     WHERE C.StoreID = @storeid
     GROUP BY P.ProductID, P.Name
);

Aşağıdaki örnek işlevi çağırır ve 602 müşteri kimliğini belirtir.

SELECT *
FROM Sales.ufn_SalesByStore(602);

Çok ifadeli tablo değer döndüren işlev (MSTVF)

Aşağıdaki örnek, AdventureWorks2025 veritabanında çoklu ifade tablo değerli bir fonksiyon (MSTVF) oluşturur. İşlev tek bir giriş parametresi, bir EmployeeID alır ve belirtilen çalışana doğrudan veya dolaylı olarak rapor veren tüm çalışanların listesini döndürür. İşlev daha sonra çalışan kimliği 109 belirterek çağrılır.

IF OBJECT_ID(N'dbo.ufn_FindReports', N'TF') IS NOT NULL
    DROP FUNCTION dbo.ufn_FindReports;
GO

CREATE FUNCTION dbo.ufn_FindReports (@InEmpID INT)
RETURNS @retFindReports TABLE
(
    EmployeeID INT PRIMARY KEY NOT NULL,
    FirstName NVARCHAR (255) NOT NULL,
    LastName NVARCHAR (255) NOT NULL,
    JobTitle NVARCHAR (50) NOT NULL,
    RecursionLevel INT NOT NULL
)
--Returns a result set that lists all the employees who report to the
--specific employee directly or indirectly.*/
AS
BEGIN
    WITH EMP_cte (EmployeeID, OrganizationNode, FirstName, LastName, JobTitle, RecursionLevel) -- CTE name and columns
    AS (
        -- Get the initial list of Employees for Manager n
        SELECT e.BusinessEntityID,
               e.OrganizationNode,
               p.FirstName,
               p.LastName,
               e.JobTitle,
               0
        FROM HumanResources.Employee AS e
             INNER JOIN Person.Person AS p
                 ON p.BusinessEntityID = e.BusinessEntityID
        WHERE e.BusinessEntityID = @InEmpID
        UNION ALL
        SELECT e.BusinessEntityID,
               e.OrganizationNode,
               p.FirstName,
               p.LastName,
               e.JobTitle,
               RecursionLevel + 1
        -- Join recursive member to anchor
        FROM HumanResources.Employee AS e
             INNER JOIN EMP_cte
                 ON e.OrganizationNode.GetAncestor(1) = EMP_cte.OrganizationNode
             INNER JOIN Person.Person AS p
                 ON p.BusinessEntityID = e.BusinessEntityID)
    -- copy the required columns to the result of the function
    INSERT @retFindReports
    SELECT EmployeeID,
           FirstName,
           LastName,
           JobTitle,
           RecursionLevel
    FROM EMP_cte;
    RETURN;
END
GO

Aşağıdaki örnek işlevi çağırır ve çalışan kimliği 1'i belirtir.

SELECT EmployeeID,
       FirstName,
       LastName,
       JobTitle,
       RecursionLevel
FROM dbo.ufn_FindReports(1);

Satır içi tablo değerli işlevler (satır içi TVF'ler) ve çok deyimli tablo değerli işlevler (MSTVF'ler) hakkında daha fazla bilgi ve örnek için bkz. CREATE FUNCTION.

En iyi yöntemler

SCHEMABINDING yan tümcesiyle kullanıcı tanımlı bir işlev (UDF) oluşturulmazsa, temel nesnelerde yapılan değişiklikler işlevin tanımını etkileyebilir ve çağrıldığında beklenmeyen sonuçlar üretebilir. temel nesnelerinde yapılan değişiklikler nedeniyle işlevin güncelliğini yitirmemesini sağlamak için aşağıdaki yöntemlerden birini uygulamanızı öneririz:

  • UDF'yi oluştururken WITH SCHEMABINDING yan tümcesini belirtin. Bu, işlev tanımında başvuruda bulunulan nesnelerin, işlev de değiştirilmediği sürece değiştirilemeyeceğini sağlar.

  • UDF tanımında belirtilen herhangi bir nesneyi değiştirdikten sonra sp_refreshsqlmodule saklı yordamını yürütün.

Verilere erişmeyen bir UDF oluşturuyorsanız, sorgu iyileştiricisinin bu UDF'leri içeren sorgu planları için gereksiz biriktirici işleçleri oluşturmasını önlemek için SCHEMABINDING seçeneğini belirtin. Biriktiriciler hakkında daha fazla bilgi için bakınız Mantıksal ve fiziksel showplan işleç referansı. Şema bağlı işlevi oluşturma hakkında daha fazla bilgi için bkz. Şemaya bağlı işlevler.

FROM yan tümcesinde MSTVF'ye katılmak mümkündür, ancak performansın düşmesine neden olabilir. SQL Server, MSTVF'ye dahil edilebilen bazı deyimlerde optimize edilmiş tekniklerin tümünü kullanamıyor, bu da optimal olmayan bir sorgu planına neden oluyor. Mümkün olan en iyi performansı elde etmek için, mümkün olduğunda işlevler yerine temel tablolar arasında birleştirmeler kullanın.

MSTVF'ler, SQL Server 2014 (12.x) ile başlayan 100 ve SQL Server'ın önceki sürümleri için 1 sabit kardinalite tahminlerine sahiptir.

SQL Server 2017 (14.x) ve sonraki sürümlerde, MSTVF'ler kullanan bir yürütme planını iyileştirmek için iç içe geçmiş yürütme kullanılabilir ve bu da daha önce bahsedilen buluşsal yöntemler yerine gerçek kardinalitenin kullanılmasına yol açar.

Daha fazla bilgi için bkz. çok deyimli tablo değerli işlevler için Birleşik yürütme.

ANSI_WARNINGS saklı yordamda, kullanıcı tanımlı işlevde parametre geçirirken veya bir batch deyiminde değişkenleri bildirdiğinizde ve ayarladığınızda kabul edilmez. Örneğin, bir değişken karakter(3) olarak tanımlanırsa ve üç karakterden büyük bir değere ayarlanırsa, veriler tanımlanan boyuta yuvarlanır ve INSERT veya UPDATE deyimi başarılı olur.