170

Can we pass a parameter to a view in Microsoft SQL Server?

I tried to create view in the following way, but it doesn't work:

create or replace view v_emp(eno number) as select * from emp where emp_id=&eno;
Himanshu
  • 31,810
  • 31
  • 111
  • 133
arunachalam
  • 1,889
  • 3
  • 13
  • 6
  • A view is a stored sql text of a select query. Parameters are out of the discussion. When your stored query returns the column where you want to filter with, you can do it in the calling query. E.g. "SELECT * FROM v_emp WHERE emp_id = ?" – Epicurist Mar 28 '17 at 09:52
  • 2
    @Epicurist `Parameters are out of the discussion` Too bold statement. [Counterexample](https://stackoverflow.com/a/49776343/5070879) – Lukasz Szozda Apr 11 '18 at 13:26
  • How about just using the Store procedure? – farid wahyu Nov 02 '22 at 02:18

22 Answers22

160

As already stated you can't.

A possible solution would be to implement a stored function, like:

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

This allows you to use it as a normal view, with:

SELECT * FROM v_emp(10)
Alex Bagnolini
  • 21,990
  • 3
  • 41
  • 41
  • 3
    What are the practical differences between this and a view? Can you assign user permissions to only access this function? – MikeMurko Oct 22 '12 at 17:44
  • In MySQL you write a stored procedure and have the last statement in the procedure be the resultset you want returned. – bobobobo Jun 06 '13 at 19:23
  • can we use that request without any problem from JDBC code in java ? – mounaim Dec 17 '14 at 13:23
  • @MikeMurko one important difference is that the schema/metadata about the columns of a view can be queried if its a view. If its stored proc or a function, then I guess databases may not be able to give you that information. – nagu Nov 14 '16 at 06:27
  • If you have a set of users who have access to your database, and you don't want them running "select * from [view]" and impacting performance, you could grant access to certain functions, which would FORCE them to provide filter parameters that, for example, leverage a certain set of index(es). – Jmoney38 Feb 22 '18 at 23:40
  • @MikeMurko The main practical difference is that with a view you can’t do it, and with a function you can. Each DBMS has its own quirks and limitations, and with SQL Server the one that applies here is that views cannot be parameterised. Another practical difference applies when you access the database from an external application. Normally you will see the tables, as well as views, which present as tables. Functions don’t. In this case it doesn’t matter since the whole point is to accept a parameter, which you wouldn’t be able to send in the external application. – Manngo Apr 14 '18 at 11:47
  • **These are not the same.** Imagine a view and a function that both return *select * from user where active = 1*. If you query *select * from fn where key=5*: the view will render as *select * from user where active=1 and key=5* whereas the function will render as *select * from (select * from user where active=1) as fn where fn.key = 5*. Point: functions are self contained subqueries. – Devin Burke Feb 22 '20 at 16:42
  • Would there be any performance issues or indexing issues by using this vs a view? – Zapnologica Jul 20 '20 at 09:23
  • I am Sorry to jump into a discussion. for me, it is an interesting solution but I am wondering to know about performance. which one is the best solution between using a function table or a store Procedure? – farid wahyu Nov 02 '22 at 02:16
42

There are two ways to achieve what you want. Unfortunately, neither can be done using a view.

You can either create a table valued user defined function that takes the parameter you want and returns a query result

Or you can do pretty much the same thing but create a stored procedure instead of a user defined function.

For example:

the stored procedure would look like

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

Or the user defined function would look like

CREATE FUNCTION u_emp
(   
    @enoNumber INT
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT    
        * 
    FROM    
        emp 
    WHERE     
        emp_id=@enoNumber
)
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
Gavin
  • 17,053
  • 19
  • 64
  • 110
  • 3
    Just keep in mind that you can't use the SP option in a `SELECT` easily: [read more](https://stackoverflow.com/a/1179778/2093077). – saastn Mar 11 '19 at 08:13
23

Normally views are not parameterized. But you could always inject some parameters. For example using session context:

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

Invocation:

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

And another:

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

DBFiddle Demo

The same is applicable for Oracle (of course syntax for context function is different).

InteXX
  • 6,135
  • 6
  • 43
  • 80
Lukasz Szozda
  • 162,964
  • 23
  • 234
  • 275
14

No you can't, as Mladen Prajdic said. Think of a view as a "static filter" on a table or a combination of tables. For example: a view may combine tables Order and Customer so you get a new "table" of rows from Order along with new columns containing the customer's name and the customer number (combination of tables). Or you might create a view that selects only unprocessed orders from the Order table (static filter).

You'd then select from the view like you would select from any other "normal" table - all "non-static" filtering must be done outside the view (like "Get all the orders for customers called Miller" or "Get unprocessed orders that came in on Dec 24th").

Thorsten Dittmar
  • 55,956
  • 8
  • 91
  • 139
10

Why do you need a parameter in view? You might just use WHERE clause.

create view v_emp as select * from emp ;

and your query should do the job:

select * from v_emp where emp_id=&eno;
Mahesh
  • 117
  • 1
  • 6
  • 13
    In some cases there will be a big performance improvement, when it's a `WHERE` for the table, instead of a `WHERE` for the view. – Doug_Ivison Dec 19 '14 at 17:50
  • While what Doug says is somewhat true, modern databases can do a remarkable job of smartly 'expanding' a view and effectively ending up with the same result as if you were to just do the full query manually. So don't assume it will be inefficient because the database may surprise you - look at the generated query plan. A notable exception would be if the view has a GROUP BY clause that affects the output - in which case you couldn't do the WHERE from the 'outside'. – Simon_Weaver Nov 07 '19 at 23:26
8

A hacky way to do it without stored procedures or functions would be to create a settings table in your database, with columns Id, Param1, Param2, etc. Insert a row into that table containing the values Id=1,Param1=0,Param2=0, etc. Then you can add a join to that table in your view to create the desired effect, and update the settings table before running the view. If you have multiple users updating the settings table and running the view concurrently things could go wrong, but otherwise it should work OK. Something like:

CREATE VIEW v_emp 
AS 
SELECT      * 
FROM        emp E
INNER JOIN  settings S
ON          S.Id = 1 AND E.emp_id = S.Param1
Bozonik
  • 89
  • 1
  • 1
  • it would terrible to use it for a request to view. But it's really usable, as a configuration/stage/environment, to use such hidden parameters. A Plus for me for that. – TPAKTOPA Apr 19 '16 at 13:26
6

no. if you must then use a user defined function to which you can pass parameters into.

Mladen Prajdic
  • 15,457
  • 2
  • 43
  • 51
5

As I know view can be something just like select command. You also can add parameters to this select for example in where statements like this:

 WHERE  (exam_id = @var)
Reza Ameri
  • 1,803
  • 3
  • 24
  • 32
5

No, a view is queried no differently to SELECTing from a table.

To do what you want, use a table-valued user-defined function with one or more parameters

MartW
  • 12,348
  • 3
  • 44
  • 68
5

A view is nothing more than a predifined 'SELECT' statement. So the only real answer would be: No, you cannot.

I think what you really want to do is create a stored procedure, where in principle you can use any valid SQL to do whatever you want, including accept parameters and select data.

It seems likely that you really only need to add a where clause when you select from your view though, but you didn't really provide enough details to be sure.

Kris
  • 40,604
  • 9
  • 72
  • 101
5

we can write a stored procedure with input parameters and then use that stored procedure to get a result set from the view. see example below.

the stored procedure is

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

and the view from which we can get the result set is

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%')  
sjngm
  • 12,423
  • 14
  • 84
  • 114
sunil
  • 51
  • 1
  • 1
4

If you don't want to use a function, you can use something like this

-- 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
        )

Hope it will help

Adnan Badar
  • 347
  • 2
  • 5
  • 14
4

No, a view is static. One thing you can do (depending on the version of SQl server) is index a view.

In your example (querying only one table), an indexed view has no benefit to simply querying the table with an index on it, but if you are doing a lot of joins on tables with join conditions, an indexed view can greatly improve performance.

John
  • 5,672
  • 7
  • 34
  • 52
3

I have an idea that I haven't tried yet. You can do:

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)

Your parameters will be saved and changed in the Config table.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Emman
  • 41
  • 2
  • 2
    If you have doubts about the veracity of a response, don't post it before you verify that it's at least an _adequate_ solution. As it stands, this is more of a question than an answer. – chb Jan 03 '19 at 07:58
  • One problem with this solution will be that if the query is being run in multiple sessions the wrong data in the config table might be used – User1010 Jun 27 '20 at 12:28
2

no you can pass the parameter to the procedure in view

aicuxiao
  • 37
  • 3
2

Here is an option I have not seen so far:

Just add the column you want to restrict on to the view:

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)
Marcel Wilson
  • 3,842
  • 1
  • 26
  • 55
FarajDaoud
  • 71
  • 1
  • 5
1

Your view can reference some external table containing your parameters.

As others mentioned, the view in SQL Server cannot have external input parameters. However, you can easily fake a variable in your view using CTE. You can test-run it in your version of 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

yielding output:

status  name
12      dbo
0       db_accessadmin
0       db_securityadmin
0       db_ddladmin

also via 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

also via 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
Oleg Melnikov
  • 3,080
  • 3
  • 34
  • 65
1

Simply use this view into stored procedure with required parameter/s (eg. in SQL Server) and parameter values in querying view.

Create stored procedure with View/ table: _spCallViewWithParameters

enter image description here

Execute procedure:

enter image description here

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Bhuwan Maharjan
  • 515
  • 4
  • 7
1

While the question is well answered, I would like to just add a point. Most of the times, we think of Views as a query that sends out the data, but a View is more than that... Views can be used to update the data in underlying tables as well. You can right-click a View in SSMS and you will find the option "Edit Top 200 rows".

I believe to enable this ability of editing data as, there are certain limitations on how query is written for View, it needs to be a static query.

So unlike a User Defined Function or Stored Procedure, which sends out the queried data and closes, a View can maintain a live connection (e.g. in Microsoft Access linked tables/views) and write the updates back to the database.

Hence, in the cases where you just want to get a set a data with certain dynamic criteria, you should use UDF/SP with the required parameters.

Uttam
  • 596
  • 1
  • 6
  • 11
0

You can bypass just to run the view, SQL will wine and cry but just do this and run it! You can't save.

create or replace view v_emp(eno number) as select * from emp where (emp_id = @Parameter1);
Kentonbmax
  • 938
  • 1
  • 10
  • 16
0

I realized this task for my needs as follows

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
cretalex
  • 1
  • 1
0

Yes, you can use SESSION_CONTEXT() function or even temp tables. Here is a complete guide for temp table approach using synonyms:

--1. prepare your data 
drop table if exists #temp_table;
select 1 as id, 'magic' as val into #temp_table; --if you change table definition (add/drop columns f.e.) you will need to recompile the view
drop synonym if exists table_synonym;
create synonym table_synonym for #temp_table;
go
--2. create a view
create or alter view some_view
as
select * from table_synonym --It is a hack and I'm not sure that it will work for your server. I test this on version 15.0.2000.5
go
--3. enjoy 
select * from some_view
go

--you can delete the synonym and the temp table without breaking some_view (but you would not be able to select the data)
drop table if exists #temp_table 
drop synonym if exists table_synonym;
go
select * from some_view 
go

BazSTR
  • 129
  • 3