157

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

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

create or replace view v_emp(eno number) as select * from emp where emp_id=&eno;
4

21 回答 21

150

如前所述,您不能。

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

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

这使您可以将其用作普通视图,其中:

SELECT * FROM v_emp(10)
于 2009-11-06T13:14:33.997 回答
39

有两种方法可以实现您想要的。不幸的是,两者都不能使用视图来完成。

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

或者您可以做几乎相同的事情,但创建一个存储过程而不是用户定义的函数。

例如:

存储过程看起来像

CREATE PROCEDURE s_emp
(
    @enoNumber INT
) 
AS 
SELECT
    * 
FROM
    emp 
WHERE 
    emp_id=@enoNumber

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

CREATE FUNCTION u_emp
(   
    @enoNumber INT
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT    
        * 
    FROM    
        emp 
    WHERE     
        emp_id=@enoNumber
)
于 2009-11-06T13:10:06.127 回答
23

通常视图没有参数化。但是你总是可以注入一些参数。例如使用会话上下文

CREATE VIEW my_view
AS
SELECT *
FROM tab
WHERE num = SESSION_CONTEXT(N'my_num');

调用:

EXEC sp_set_session_context 'my_num', 1; 
SELECT * FROM my_view;

还有一个:

EXEC sp_set_session_context 'my_num', 2; 
SELECT * FROM my_view;

DBFiddle 演示

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

于 2018-04-11T13:24:38.303 回答
14

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

然后,您可以像从任何其他“正常”表中选择一样从视图中进行选择 - 所有“非静态”过滤必须在视图之外完成(例如“获取名为 Miller 的客户的所有订单”或“获取未处理的订单” 12 月 24 日进来的”)。

于 2009-11-06T13:03:01.867 回答
10

为什么需要查看参数?您可能只使用WHERE子句。

create view v_emp as select * from emp ;

您的查询应该可以完成这项工作:

select * from v_emp where emp_id=&eno;
于 2013-04-05T19:42:01.513 回答
8

在没有存储过程或函数的情况下执行此操作的一种 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
于 2012-06-26T10:00:56.110 回答
6

不。如果您必须使用用户定义的函数,您可以将参数传递给该函数。

于 2009-11-06T12:32:55.470 回答
5

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

做你想做的事,使用带有一个或多个参数的表值用户定义函数

于 2009-11-06T13:07:39.043 回答
5

视图只不过是一个预定义的“SELECT”语句。所以唯一真正的答案是:不,你不能。

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

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

于 2009-11-06T13:16:02.887 回答
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

我们可以从中获得结果集的视图是

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%')  
于 2011-04-07T14:34:03.007 回答
5

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

 WHERE  (exam_id = @var)
于 2012-09-16T19:01:45.137 回答
4

如果您不想使用功能,可以使用类似这样的东西

-- VIEW
CREATE VIEW [dbo].[vwPharmacyProducts]
AS
SELECT     PharmacyId, ProductId
FROM         dbo.Stock
WHERE     (TotalQty > 0)

-- Use of view inside a stored procedure
CREATE PROCEDURE [dbo].[usp_GetProductByFilter]
(   @pPharmacyId int ) AS

IF @pPharmacyId = 0 BEGIN SET @pPharmacyId = NULL END

SELECT  P.[ProductId], P.[strDisplayAs] FROM [Product] P
WHERE (P.[bDeleted] = 0)
    AND (P.[ProductId] IN (Select vPP.ProductId From vwPharmacyProducts vPP
                           Where vPP.PharmacyId = @pPharmacyId)
                       OR @pPharmacyId IS NULL
        )

希望它会有所帮助

于 2013-05-15T08:11:10.167 回答
4

不,视图是静态的。您可以做的一件事(取决于 SQl 服务器的版本)是索引视图。

在您的示例中(仅查询一个表),索引视图与简单地查询带有索引的表没有任何好处,但是如果您对带有连接条件的表进行大量连接,则索引视图可以大大提高性能。

于 2009-11-06T17:52:17.687 回答
3

不,您可以将参数传递给视图中的过程

于 2009-11-06T13:14:31.830 回答
2

这是我到目前为止还没有看到的一个选项:

只需将要限制的列添加到视图中:

create view emp_v as (
select emp_name, emp_id from emp;
)

select emp_v.emp_name from emp_v
where emp_v.emp_id = (id to restrict by)
于 2017-01-17T15:46:59.133 回答
1

您的视图可以引用一些包含您的参数的外部表。

正如其他人提到的,SQL Server 中的视图不能有外部输入参数。但是,您可以使用 CTE 在视图中轻松伪造变量。您可以在您的 SQL Server 版本中测试运行它。

CREATE VIEW vwImportant_Users AS
WITH params AS (
    SELECT 
    varType='%Admin%', 
    varMinStatus=1)
SELECT status, name 
    FROM sys.sysusers, params
    WHERE status > varMinStatus OR name LIKE varType

SELECT * FROM vwImportant_Users

产生输出:

status  name
12      dbo
0       db_accessadmin
0       db_securityadmin
0       db_ddladmin

也通过JOIN

WITH params AS ( SELECT varType='%Admin%', varMinStatus=1)
SELECT status, name 
    FROM sys.sysusers INNER JOIN params ON 1=1
    WHERE status > varMinStatus OR name LIKE varType

也通过CROSS APPLY

WITH params AS ( SELECT varType='%Admin%', varMinStatus=1)
SELECT status, name 
    FROM sys.sysusers CROSS APPLY params
    WHERE status > varMinStatus OR name LIKE varType
于 2017-12-12T22:32:45.273 回答
1

您可以绕过只是为了运行视图,SQL 会大喊大叫,但只需执行此操作并运行它!你不能保存。

create or replace view v_emp(eno number) as select * from emp where (emp_id = @Parameter1);
于 2016-04-06T16:31:13.330 回答
1

我有一个想法,我还没有尝试过。你可以做:

CREATE VIEW updated_customers AS
SELECT * FROM customer as aa
LEFT JOIN customer_rec as bb
ON aa.id = bb.customer_id
WHERE aa.updated_at between (SELECT start_date FROM config WHERE active = 1) 
and (SELECT end_date FROM config WHERE active = 1)

您的参数将在配置表中保存和更改。

于 2019-01-03T07:38:02.403 回答
0

只需将此视图用于带有所需参数(例如在 SQL Server 中)和查询视图中的参数值的存储过程。

使用 View/ 表创建存储过程:_spCallViewWithParameters

在此处输入图像描述

执行程序:

在此处输入图像描述

于 2020-10-02T23:47:14.637 回答
0

虽然这个问题得到了很好的回答,但我想补充一点。大多数时候,我们将视图视为发送数据的查询,但视图不止于此……视图也可用于更新基础表中的数据。您可以右键单击 SSMS 中的视图,您将找到“编辑前 200 行”选项。

我相信要启用这种编辑数据的能力,因为如何为 View 编写查询有一定的限制,它需要是一个静态查询。

因此,与发送查询数据并关闭的用户定义函数或存储过程不同,视图可以维持实时连接(例如在 Microsoft Access 链接表/视图中)并将更新写回数据库。

因此,在您只想获取具有某些动态标准的数据集的情况下,您应该使用带有所需参数的 UDF/SP。

于 2021-03-14T03:53:36.577 回答
0

我根据我的需要实现了这个任务,如下所示

set nocount on;

  declare @ToDate date = dateadd(month,datediff(month,0,getdate())-1,0)

declare @year varchar(4)  = year(@ToDate)
declare @month varchar(2) = month(@ToDate)

declare @sql nvarchar(max)
set @sql = N'
    create or alter view dbo.wTempLogs
    as
    select * from dbo.y2019
    where
        year(LogDate) = ''_year_''
        and 
        month(LogDate) = ''_month_''    '

select @sql = replace(replace(@sql,'_year_',@year),'_month_',@month)

execute sp_executesql @sql

declare @errmsg nvarchar(max)
    set @errMsg = @sql
    raiserror (@errMsg, 0,1) with nowait
于 2019-10-03T06:20:33.747 回答