使用存储过程创建视图时出错

Dot*_*row 1 t-sql stored-procedures dynamic-sql sql-server-2008 sql-view

我有以下存储过程创建一个视图:

ALTER PROC Proc_Guards_By_Client
(
    @client_number INT,
    @client_name   NVARCHAR(16)
)
AS
 BEGIN
   IF EXISTS(select * FROM sys.views where name = 'vwGuardsByClients')
   BEGIN
    EXEC ('CREATE VIEW vwGuardsByClients
    AS
    SELECT TOP 1000 
      cgt.[guard_id],
      sg.first_name,
      sg.last_name,
      sg.ammunition_quantity    
      FROM [sws4].[dbo].[client_guard_tracking] cgt
      INNER JOIN CLIENTS c
      ON c.client_number = cgt.client_number
      INNER JOIN security_guard sg
      ON sg.guard_id = cgt.guard_id
      WHERE cgt.client_number = @client_number
      OR c.client_name = @client_name
    ')
    END
    ELSE
    BEGIN
      EXEC ('UPDATE VIEW vwGuardsByClients
      SELECT TOP 1000 
      cgt.[guard_id],
      sg.first_name,
      sg.last_name,
      sg.ammunition_quantity    
      FROM [sws4].[dbo].[client_guard_tracking] cgt
      INNER JOIN CLIENTS c
      ON c.client_number = cgt.client_number
      INNER JOIN security_guard sg
      ON sg.guard_id = cgt.guard_id
      WHERE cgt.client_number = @client_number
      OR c.client_name = @client_name
    ')
    END

    IF @@ROWCOUNT = 0
        PRINT 'Warning: No rows were updated'
 END
Run Code Online (Sandbox Code Playgroud)

但是当我执行它时,我得到:

Msg 156, Level 15, State 1, Line 2
Incorrect syntax near the keyword 'VIEW'.

Msg 137, Level 15, State 2, Line 14
Must declare the scalar variable "@client_number".
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 5

仍有各种问题.正如你昨天所做的那样,当你承认它倒退时,你仍然会倒退你的逻辑.怎么还是错的?现在它说:

如果视图已经存在:
      让我们创建它!

否则,如果视图尚不存在:
      让我们编辑它!

下一个问题是您使用语法UPDATE VIEW.昨天你试图使用CREATE OR REPLACE.两者都没有效.你需要ALTER VIEW.

你还在用它@@ROWCOUNT来检查是否成功.这不是成功创建或更改视图的有效检查(也可能不适合更新/删除检查,但这是一个不同的问题).正如我昨天解释的那样,你应该TRY/CATCH为此而使用.

最后,你试图连接内部的变量EXEC()- 并且你追加一个字符串变量忽略了它包含撇号(')的可能性,它会破坏你的查询(这里也可能存在SQL注入问题).为此你应该使用sp_executeSQL.事实上更好的是不要浪费地重复所有的视图代码:

ALTER PROCEDURE dbo.Proc_Guards_By_Client
  @client_number  INT,
  @client_name    NVARCHAR(16)
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @sql NVARCHAR(MAX) = N' VIEW dbo.vmGuardsByClient
    AS
      SELECT ... rest of view code ...
      WHERE cgt.client_number = ' + CONVERT(VARCHAR(12), @client_number) + 
       ' OR c.client_name = ''' + REPLACE(@client_name, '''', '''''') + ''';';

  SET @sql = CASE WHEN EXISTS
    (SELECT 1 FROM sys.views WHERE [object_id] = OBJECT_ID('dbo.vwGuardsByClients'))
    THEN N'ALTER' ELSE N'CREATE' + @sql;

  BEGIN TRY
    EXEC sp_executesql @sql;
  END TRY
  BEGIN CATCH
    PRINT ERROR_MESSAGE();
  END CATCH
END
GO
Run Code Online (Sandbox Code Playgroud)

不过,我不得不问.为什么需要为特定视图创建一个不知道视图是否已存在的存储过程?一旦你创建了这个视图一次,CREATE VIEW代码部分将如何再次执行?您的所有用户都拥有dbo/sa权限吗?此视图是否真的有被丢弃的危险?您是否尝试为每个客户创建一个视图?如果是这样,您最好考虑将客户端名称添加到视图的名称中.在当前场景中,每当新客户端尝试运行代码时,您将替换现有视图,然后当先前用户从视图中进行选择时,他们会惊讶于他们不再看到自己的数据.