首页 > 解决方案 > 将存储过程转换为函数

问题描述

由于 Direct Query 数据连接模式,我需要使用一个函数才能通过 Power BI 使用它,Power BI 无法使用存储过程。

因此,我正在尝试从存储过程创建一个函数。

以下是我要从中创建函数的存储过程:

ALTER PROCEDURE [dbo].[SPTest]   
    @Anio int,
    @Mes int
AS
BEGIN
    DECLARE @AnioMes  varchar(8),
            @AnioMes6 varchar(8)

    IF @Anio IS NULL
        SELECT @Anio = YEAR(GETDATE()),
               @Mes  = MONTH(GETDATE())

    SELECT 
        @AnioMes = (CASE WHEN @Mes = 12 THEN @Anio + 1 ELSE @Anio END * 100 + 
                    CASE WHEN @Mes = 12 THEN 1 ELSE @Mes + 1 END) * 100 + 1
    SELECT
        @AnioMes6 = CONVERT(varchar(8), DATEADD(mm, -5, @AnioMes), 112)

    SELECT 
        YEAR(DATEADD(second, DATEDIFF(second, GETUTCDATE(), GETDATE()), CREATEDDATETIME)) * 100 + 
        MONTH(DATEADD(second, DATEDIFF(second, GETUTCDATE(), GETDATE()), CREATEDDATETIME)) AS AnioMes,
        DATEADD(second, DATEDIFF(second, GETUTCDATE(), GETDATE()), CREATEDDATETIME) AS FECHA_CREACION,
        INPUTSUBJECT,
        CASE 
            WHEN TOWTYPE = 1 THEN 'T1'
            WHEN TOWTYPE = 2 THEN 'T2'
            WHEN TOWTYPE = 3 THEN 'T3'
            WHEN TOWTYPE = 4 THEN 'T4'
            ELSE ''
        END AS TOWTYPE,
        [VENDNAME]
    FROM 
        TRUCKS
    WHERE
        YEAR(DATEADD(second, DATEDIFF(second, GETUTCDATE(), GETDATE()), CREATEDDATETIME)) >= yEAR(@AnioMes6)
        AND MONTH(DATEADD(second, DATEDIFF(second, GETUTCDATE(), GETDATE()), CREATEDDATETIME)) <= MONTH(@AnioMes)
        AND DATEADD(second, DATEDIFF(second, GETUTCDATE(), GETDATE()), CREATEDDATETIME) >= '20160701'

希望有人能给我一些关于如何从这个存储过程创建函数的指导

我试图做以下事情:

CREATE FUNCTION [dbo].[SPTest]
(
    @Anio   int,
    @Mes    int,
    @AnioMes    varchar(8),
    @AnioMes6   varchar(8)
)
RETURNS TABLE
AS
BEGIN

        if @Anio is null
        Select  @Anio   = YEAR(GETDATE()),
                @Mes    = MONTH(GETDATE())

    Select  @AnioMes    = (case when @Mes=12 then @Anio+1 else @Anio end *100 + Case when @Mes=12 then 1 else @Mes+1 end)*100 + 1
    Select  @AnioMes6   = convert(varchar(8), DATEADD(mm, -5, @AnioMes), 112 )


    SELECT year(DATEADD(second, DATEDIFF(second, GETUTCDATE(), GETDATE()), CREATEDDATETIME))*100+month(DATEADD(second, DATEDIFF(second, GETUTCDATE(), GETDATE()), CREATEDDATETIME)) as AnioMes
          ,DATEADD(second, DATEDIFF(second, GETUTCDATE(), GETDATE()), CREATEDDATETIME) as FECHA_CREACION
          ,INPUTSUBJECT
          ,Case When TOWTYPE = 1 then 'T1'
                When TOWTYPE = 2 then 'T2'
                When TOWTYPE = 3 then 'T3'
                When TOWTYPE = 4 then 'T4'
                Else ''
            End as TOWTYPE
          ,[VENDNAME]
        FROM TRUCKS
        Where   year(DATEADD(second, DATEDIFF(second, GETUTCDATE(), GETDATE()), CREATEDDATETIME)) >= yEAR(@AnioMes6)
        and month(DATEADD(second, DATEDIFF(second, GETUTCDATE(), GETDATE()), CREATEDDATETIME)) <= MONTH(@AnioMes)
        AND     DATEADD(second, DATEDIFF(second, GETUTCDATE(), GETDATE()), CREATEDDATETIME) >= '20160701'

    END 

    RETURN

我在 BEGIN 中收到以下错误:

BEGIN 附近的语法不正确

标签: sqlsql-servertsqlstored-procedures

解决方案


首先,您应该始终尝试坚持使用内联表值函数,因为它们的性能要好得多。

内联函数没有BEGINorEND并且只能包含一个AS RETURN SELECT语句。

  • 注意变量是如何转换为VALUES子句的
  • 避免对列使用函数。无需转换CREATEDDATETIME为时区进行比较,而是将您的参数转换为 UTC
  • 出于同样的原因,不要比较日期的各个部分,构建起点和终点并与之进行比较
  • 不要使用字符串转换来创建日期,它很慢并且可能是不确定的。而是使用可用的适当日期函数
CREATE OR ALTER FUNCTION [dbo].[SPTest] (
    @month DATETIME
)
RETURNS TABLE
AS RETURN

SELECT
   v1.AnioMes
  ,t.CREATEDDATETIME AT TIME ZONE 'YourTimeZoneHere' as FECHA_CREACION
  ,t.INPUTSUBJECT
  ,CASE WHEN t.TOWTYPE IN (1,2,3,4)
        THEN CONCAT('T', t.TOWTYPE)
        ELSE '' END AS TOWTYPE
  ,t.[VENDNAME]

FROM (VALUES (
    DATEADD(day, 1, EOMONTH(TODATETIMEOFFSET(@month, 0)))
)) v1(AnioMes)

CROSS APPLY (VALUES (
    DATEADD(month, -5, v1.AnioMes)
)) v2(AnioMes6)

CROSS JOIN TRUCKS t

WHERE t.CREATEDDATETIME >= v2.AnioMes6
  AND t.CREATEDDATETIME <  v1.AnioMes
  AND t.CREATEDDATETIME >= '20160701';

推荐阅读