【问题标题】:How to exec a create view with variables如何使用变量执行创建视图
【发布时间】:2019-01-17 09:58:32
【问题描述】:

我试图在每次程序运行时执行一个视图。 我的代码有什么问题?为什么它不起作用?

CREATE PROCEDURE dbo.MTBFAlterView @PressType nvarchar(50), @TestName nvarchar(50), @PressName nvarchar(50), @Phase nvarchar(50)
AS
--Failure Report Table
DECLARE @ViewDROP nvarchar(MAX) = 'DROP VIEW [dbo].[UV_filteredLogins]'
DECLARE @ParmDefinition nvarchar(500);  
 DECLARE @STMT AS NVARCHAR(MAX) = N'
                                    Create VIEW [dbo].[UV_filteredLogins]
                                    as
                                    SELECT logins.[ID]
                                        ,[Test_ID]
                                        ,phase.Phase_Name
                                        ,press.PressName
                                        ,pressType.Type_Description as PressType
                                        ,[Operator]
                                        ,[LoginDate]
                                        ,[LogoutDate]
                                        ,DATEDIFF(MINUTE,LoginDate,LogoutDate) as TimeDiff
                                    FROM [TDM_Analysis].[dbo].[Logins] as logins join [TDM_Analysis].[dbo].[Presses] as press on logins.Press_ID=press.ID 
                                    join [TDM_Analysis].[dbo].[Phases] as phase on logins.Phase_ID=phase.ID 
                                    join [TDM_Analysis].[dbo].[PressTypes] as pressType on pressType.ID=press.PressType_ID
                                    join [TDM_Analysis].[dbo].[Tests] as test on logins.Test_ID=test.ID
                                    where phase.Phase_Name= @Phase1 and press.PressName= @PressName1 and pressType.Type_Description=@PressType1 and [Test_ID]=TestName1 and logoutDate is not null
                                        and Operator in (SELECT au.Email
                                                        FROM [UsersAuthorization].[dbo].[RolesMembers] as RM join [UsersAuthorization].[dbo].[ApplicationUsers] as AU on RM.ApplicationUserID=au.ID
                                                        where rm.roleid=1)';
    SET @ParmDefinition=N'@PressType1 nvarchar(50), @TestName1 nvarchar(50), @PressName1 nvarchar(50), @Phase1 nvarchar(50) OUTPUT'; 
    --EXEC sp_executesql @ViewDROP
   EXEC sp_executesql @STMT, @ParmDefinition, @PressType1 = @PressType, @TestName1=@TestName, @PressName1=@PressName, @Phase1=@Phase OUTPUT;



   exec dbo.MTBFAlterView @PressType='HP Indigo 10000', @TestName='Go Green', @PressName='MR-193', @Phase='Test'

我的结果是: 消息 156,第 15 级,状态 1,第 34 行 关键字“VIEW”附近的语法不正确。

【问题讨论】:

  • 编辑你的代码我认为你在视图中缺少@:
  • 为什么需要这样做?你到底想做什么?似乎每次都删除视图并重新创建不是一个好主意。
  • @Sami 嗨,我毕竟没有执行删除,我正在尝试使用我将从用户那里获得的参数创建\更改视图。
  • 您必须在创建查询中传递值而不是变量(@PressName1)
  • 视图的定义中不能有变量。您是否希望将这些变量转换为 VIEW 定义中的文字值?

标签: sql sql-server view sp-executesql


【解决方案1】:

视图不带参数。如果您想在使用视图的时间点传递参数,您可以定义一个table-valued user defined function

但是,这里看起来您正在尝试设置参数单独从使用视图的位置。在这里,最好的选择可能是视图的某种形式的“参数表”,例如:

CREATE TABLE UV_filteredLogins_parms (
    Lock char(1) not null,
    constraint CK_UV_filteredLogins_Locked CHECK (Lock = 'X'),
    constraint PK_UV_filteredLogins PRIMARY KEY (Lock),
    PressType nvarchar(50),
    TestName nvarchar(50),
    PressName nvarchar(50),
    Phase nvarchar(50)
)

现在,上表可以包含 0 行或 1 行。我建议您只插入一行,然后让您的存储过程针对它发出UPDATE

现在,在视图中,您可以简单地加入此表,然后将这些列值与其他表中的列进行比较1。每当参数值发生变化时,您都不需要删除并重新创建它。

我不知道为什么 @Phase 被标记为 OUTPUT


1CROSS JOIN 并继续在WHEREINNER JOIN 中进行实际比较,并将部分/全部比较移到它的ON 子句中。

【讨论】:

    【解决方案2】:

    如果您希望传递的参数是 VIEW 定义中的文字值,那么这就是您想要构建它的方式:

    CREATE PROCEDURE dbo.MTBFAlterView @PressType nvarchar(50), @TestName nvarchar(50), @PressName nvarchar(50), @Phase nvarchar(50)
    AS BEGIN
    
        IF EXISTS (SELECT 1 FROM sys.objects WHERE [name] = 'UV_filteredLogins')
            DROP VIEW UV_filteredLogins;
    
        DECLARE @SQL nvarchar(MAX) = N'
    CREATE VIEW [dbo].[UV_filteredLogins]
    AS
        SELECT logins.[ID],
               [Test_ID],
               phase.Phase_Name,
               press.PressName,
               pressType.Type_Description AS PressType,
               [Operator],
               [LoginDate],
               [LogoutDate],
               DATEDIFF(MINUTE, LoginDate, LogoutDate) AS TimeDiff
        FROM [TDM_Analysis].[dbo].[Logins] logins
             JOIN [TDM_Analysis].[dbo].[Presses] press ON logins.Press_ID = press.ID
             JOIN [TDM_Analysis].[dbo].[Phases] phase ON logins.Phase_ID = phase.ID
             JOIN [TDM_Analysis].[dbo].[PressTypes] pressType ON pressType.ID = press.PressType_ID
             JOIN [TDM_Analysis].[dbo].[Tests] test ON logins.Test_ID = test.ID
        WHERE phase.Phase_Name = ' + QUOTENAME(@Phase,N'''') + N'
          AND press.PressName = ' + QUOTENAME(@PressName,N'''') + N'
          AND pressType.Type_Description = ' + QUOTENAME(@PressType,N'''') + N'
          AND [Test_ID] = TestName1
          AND logoutDate IS NOT NULL
          AND Operator IN (SELECT AU.Email
                           FROM [UsersAuthorization].[dbo].[RolesMembers] RM
                                JOIN [UsersAuthorization].[dbo].[ApplicationUsers] AU ON RM.ApplicationUserID = AU.ID
                           WHERE RM.roleid = 1);';
    
        EXEC sp_executesql @SQL;
    END
    GO
    

    注意这里使用QUOTENAME。这可以通过在生成值时适当地引用这些值来保证动态 SQL 的安全。因此,例如,像“don't”这样的值将被解析为'don''t'。这避免了您的 SP 中的注入,这在使用动态 SQL 时非常重要。

    【讨论】:

      【解决方案3】:

      我猜,你想要这个 SP。

      CREATE PROCEDURE dbo.MTBFAlterView @PressType nvarchar(50), @TestName nvarchar(50) 
      , @PressName nvarchar(50), @Phase nvarchar(50)
      
      AS
      --Failure Report Table
      begin
       DECLARE @ViewDROP nvarchar(MAX) = N'DROP VIEW [dbo].[UV_filteredLogins]' -- 'N' has been added
       DECLARE @ParmDefinition nvarchar(500);  
       DECLARE @STMT AS NVARCHAR(MAX) = N'
        Create VIEW [dbo].[UV_filteredLogins]
        as
        SELECT logins.[ID]
         , [Test_ID]
         , phase.Phase_Name
         , press.PressName
         , pressType.Type_Description as PressType
         , [Operator]
         , [LoginDate]
         , [LogoutDate]
         , DATEDIFF(MINUTE,LoginDate,LogoutDate) as TimeDiff
        FROM [TDM_Analysis].[dbo].[Logins]        as logins 
        join [TDM_Analysis].[dbo].[Presses]       as press on logins.Press_ID=press.ID 
        join [TDM_Analysis].[dbo].[Phases]        as phase on logins.Phase_ID=phase.ID 
        join [TDM_Analysis].[dbo].[PressTypes]    as pressType on pressType.ID=press.PressType_ID
        join [TDM_Analysis].[dbo].[Tests]         as test on logins.Test_ID=test.ID
        where phase.Phase_Name= '''+@Phase +''' and press.PressName= '''+ @PressName +''' 
        and pressType.Type_Description= '''+@PressType +
        /*Parameter's values are applied in WHERE condition*/
        ''' and [Test_ID]=TestName1 and logoutDate is not null
        and Operator in (
         SELECT au.Email
         FROM [UsersAuthorization].[dbo].[RolesMembers] as RM 
         join [UsersAuthorization].[dbo].[ApplicationUsers] as AU 
         on RM.ApplicationUserID=au.ID
         where rm.roleid=1
        )';
      
      
        EXEC sp_executesql @STMT              -- View will be created.
        select * from UV_filteredLogins       -- Call it.
        --EXEC sp_executesql @ViewDROP        -- Drop query of view.
      end
      
      exec dbo.MTBFAlterView 'HP Indigo 10000', 'Go Green'
      , 'MR-193','Test'
      -- If you call this, then view is created and followed by 'SELECT'
      

      【讨论】:

      • 写动态SQL时请考虑注入。这对它很开放。
      • @Larnu.. 我对注射一无所知。所以让我研究一下注射。
      • 我当然推荐阅读有关 Injection 的文章;使您的(动态)SQL 安全是一项非常宝贵的技能。
      猜你喜欢
      • 2012-01-21
      • 2021-04-19
      • 1970-01-01
      • 2016-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多