我们可以将参数传递给SQL中的视图吗?

aru*_*lam 119 sql sql-server parameters views parameter-passing

我们可以将参数传递给Microsoft SQL Server中的视图吗?

我尝试以create view下列方式,但它不起作用:

create or replace view v_emp(eno number) as select * from emp where emp_id=&eno;
Run Code Online (Sandbox Code Playgroud)

Ale*_*ini 118

如前所述,你不能.

一种可能的解决方案是实现存储的函数,如:

CREATE FUNCTION v_emp (@pintEno INT)
RETURNS TABLE
AS
RETURN
   SELECT * FROM emp WHERE emp_id=@pintEno;
Run Code Online (Sandbox Code Playgroud)

这允许您将其用作普通视图,具有:

SELECT * FROM v_emp(10)
Run Code Online (Sandbox Code Playgroud)

  • 这和视图之间有什么实际区别?您可以分配用户权限仅访问此功能吗? (3认同)

Gav*_*vin 33

有两种方法可以实现你想要的不幸,也无法使用视图.

您可以创建一个表值用户定义函数,该函数获取您想要的参数并返回查​​询结果

或者你可以做同样的事情,但创建一个存储过程而不是用户定义的函数.

例如

存储过程看起来像

CREATE PROCEDURE s_emp
(
    @enoNumber INT
) 
AS 
SELECT
    * 
FROM
    emp 
WHERE 
    emp_id=@enoNumber
Run Code Online (Sandbox Code Playgroud)

或者用户定义的函数看起来像

CREATE FUNCTION u_emp
(   
    @enoNumber INT
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT    
        * 
    FROM    
        emp 
    WHERE     
        emp_id=@enoNumber
)
Run Code Online (Sandbox Code Playgroud)

  • 请记住,您无法轻松地在“SELECT”中使用 SP 选项:[阅读更多](/sf/answers/82584491/)。 (3认同)

Tho*_*mar 13

不,你不能,正如Mladen Prajdic所说.将视图视为表或表组合的"静态过滤器".例如:视图可以组合表Order,Customer因此您将获得一个新的行"表" Order以及包含客户名称和客户编号(表的组合)的新列.或者您可以创建一个视图,仅从Order表中选择未处理的订单(静态过滤器).

然后,您可以从视图中选择,就像从任何其他"普通"表中选择一样 - 所有"非静态"过滤必须在视图外部完成(例如"获取客户的所有订单,称为Miller"或"获取未处理的订单")这是在12月24日发布的").


Luk*_*zda 10

通常情况下,视图不是参数化的.但你总是可以注入一些参数.例如,使用会话上下文:

CREATE VIEW my_view
AS
SELECT *
FROM tab
WHERE num = SESSION_CONTEXT(N'my_num');
Run Code Online (Sandbox Code Playgroud)

调用:

EXEC sp_set_session_context 'my_num', 1; 
SELECT * FROM my_view;
Run Code Online (Sandbox Code Playgroud)

而另一个:

EXEC sp_set_session_context 'my_num', 2; 
SELECT * FROM my_view;
Run Code Online (Sandbox Code Playgroud)

DBFiddle演示

这同样适用于Oracle(当然上下文函数的语法也不同).

  • 我认为这非常方便.类似于如何将参数传递给Web应用程序(例如Java). (2认同)

小智 8

为什么在视图中需要参数?你可以只使用WHERE子句.

create view v_emp as select * from emp ;
Run Code Online (Sandbox Code Playgroud)

你的查询应该做的工作:

select * from v_emp where emp_id=&eno;
Run Code Online (Sandbox Code Playgroud)

  • 在某些情况下,当它是表的"WHERE"而不是视图的"WHERE"时,将会有很大的性能提升. (11认同)

小智 7

没有存储过程或函数的hacky方法是在数据库中创建一个设置表,列Id,Param1,Param2等.在该表中插入一行,其中包含值Id = 1,Param1 = 0,Param2 = 0等.然后,您可以在视图中为该表添加连接以创建所需的效果,并在运行视图之前更新设置表.如果您有多个用户更新设置表并同时运行视图,则可能会出错,但除此之外它应该可以正常工作.就像是:

CREATE VIEW v_emp 
AS 
SELECT      * 
FROM        emp E
INNER JOIN  settings S
ON          S.Id = 1 AND E.emp_id = S.Param1
Run Code Online (Sandbox Code Playgroud)

  • 你是对的.这是一个可怕的解决方案. (13认同)

Mla*_*dic 6

没有.如果必须使用可以将参数传递到的用户定义函数.


Mar*_*rtW 5

不,查询视图与从表中进行选择没有什么不同。

若要执行所需操作,请使用带有一个或多个参数的表值用户定义函数


Kri*_*ris 5

视图只不过是一个预先设定的'SELECT'语句.所以唯一真正的答案是:不,你不能.

我认为你真正想要做的是创建一个存储过程,原则上你可以使用任何有效的SQL来做任何你想做的事情,包括接受参数和选择数据.

当你从视图中选择时,你真的只需要添加一个where子句,但是你并没有真正提供足够的细节来确定.


小智 5

我们可以使用输入参数编写存储过程,然后使用该存储过程从视图中获取结果集.见下面的例子.

存储过程是

CREATE PROCEDURE [dbo].[sp_Report_LoginSuccess] -- [sp_Report_LoginSuccess] '01/01/2010','01/30/2010'
@fromDate datetime,
@toDate datetime,
@RoleName varchar(50),
@Success int
as
If @RoleName != 'All'
Begin
   If @Success!=2
   Begin
   --fetch based on true or false
  Select * from vw_Report_LoginSuccess
  where logindatetime between  dbo.DateFloor(@fromDate) and dbo.DateSieling(@toDate)
  And RTrim(Upper(RoleName)) = RTrim(Upper(@RoleName)) and Success=@Success
   End
   Else
   Begin
    -- fetch all
  Select * from vw_Report_LoginSuccess
  where logindatetime between  dbo.DateFloor(@fromDate) and dbo.DateSieling(@toDate)
  And RTrim(Upper(RoleName)) = RTrim(Upper(@RoleName))
   End

End
Else
Begin
   If @Success!=2
   Begin
  Select * from vw_Report_LoginSuccess
  where logindatetime between  dbo.DateFloor(@fromDate) and dbo.DateSieling(@toDate)
  and Success=@Success
 End
 Else
 Begin
  Select * from vw_Report_LoginSuccess
  where logindatetime between  dbo.DateFloor(@fromDate) and dbo.DateSieling(@toDate)
 End

End
Run Code Online (Sandbox Code Playgroud)

以及我们可以从中获取结果集的视图

CREATE VIEW [dbo].[vw_Report_LoginSuccess]
AS
SELECT     '3' AS UserDetailID, dbo.tblLoginStatusDetail.Success, CONVERT(varchar, dbo.tblLoginStatusDetail.LoginDateTime, 101) AS LoginDateTime,
                      CONVERT(varchar, dbo.tblLoginStatusDetail.LogoutDateTime, 101) AS LogoutDateTime, dbo.tblLoginStatusDetail.TokenID,
                      dbo.tblUserDetail.SubscriberID, dbo.aspnet_Roles.RoleId, dbo.aspnet_Roles.RoleName
FROM         dbo.tblLoginStatusDetail INNER JOIN
                      dbo.tblUserDetail ON dbo.tblLoginStatusDetail.UserDetailID = dbo.tblUserDetail.UserDetailID INNER JOIN
                      dbo.aspnet_UsersInRoles ON dbo.tblUserDetail.UserID = dbo.aspnet_UsersInRoles.UserId INNER JOIN
                      dbo.aspnet_Roles ON dbo.aspnet_UsersInRoles.RoleId = dbo.aspnet_Roles.RoleId
WHERE     (dbo.tblLoginStatusDetail.Success = 0)
UNION all
SELECT     dbo.tblLoginStatusDetail.UserDetailID, dbo.tblLoginStatusDetail.Success, CONVERT(varchar, dbo.tblLoginStatusDetail.LoginDateTime, 101)
                      AS LoginDateTime, CONVERT(varchar, dbo.tblLoginStatusDetail.LogoutDateTime, 101) AS LogoutDateTime, dbo.tblLoginStatusDetail.TokenID,
                      dbo.tblUserDetail.SubscriberID, dbo.aspnet_Roles.RoleId, dbo.aspnet_Roles.RoleName
FROM         dbo.tblLoginStatusDetail INNER JOIN
                      dbo.tblUserDetail ON dbo.tblLoginStatusDetail.UserDetailID = dbo.tblUserDetail.UserDetailID INNER JOIN
                      dbo.aspnet_UsersInRoles ON dbo.tblUserDetail.UserID = dbo.aspnet_UsersInRoles.UserId INNER JOIN
                      dbo.aspnet_Roles ON dbo.aspnet_UsersInRoles.RoleId = dbo.aspnet_Roles.RoleId
WHERE     (dbo.tblLoginStatusDetail.Success = 1) AND (dbo.tblUserDetail.SubscriberID LIKE N'P%')  
Run Code Online (Sandbox Code Playgroud)


Rez*_*eri 5

据我所知,视图可以像select命令一样.您还可以向此选择添加参数,例如在where语句中:

 WHERE  (exam_id = @var)
Run Code Online (Sandbox Code Playgroud)