SQL의 뷰에 매개 변수를 전달할 수 있습니까?


138

Microsoft SQL Server의 뷰에 매개 변수를 전달할 수 있습니까?

create view다음과 같은 방법으로 시도했지만 작동하지 않습니다.

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

뷰는 선택 쿼리의 저장된 SQL 텍스트입니다. 매개 변수는 논의에서 벗어났습니다. 저장된 쿼리가 필터링하려는 열을 반환하면 호출 쿼리에서 수행 할 수 있습니다. 예 : "SELECT * FROM v_emp WHERE emp_id =?"
Epicurist

2
@Epicurist Parameters are out of the discussion너무 대담한 진술. 반례
Lukasz Szozda

답변:


132

이미 언급했듯이 할 수 없습니다.

가능한 해결책은 다음과 같은 저장 함수를 구현하는 것입니다.

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

이를 통해 다음과 같이 일반보기로 사용할 수 있습니다.

SELECT * FROM v_emp(10)

이보기와보기의 실제 차이점은 무엇입니까? 이 기능에만 액세스 할 수있는 사용자 권한을 할당 할 수 있습니까?
MikeMurko

MySQL에서는 저장 프로 시저를 작성하고 프로 시저의 마지막 문장을 반환하려는 결과 집합이되게합니다.
bobobobo 2016

Java의 JDBC 코드에서 아무런 문제없이 해당 요청을 사용할 수 있습니까?
mounaim

@ MikeMurko의 중요한 차이점 중 하나는 뷰의 열에 대한 스키마 / 메타 데이터가 뷰인 경우 쿼리 할 수 ​​있다는 것입니다. 저장된 proc 또는 함수 인 경우 데이터베이스가 해당 정보를 제공하지 못할 수 있습니다.
nagu

데이터베이스에 액세스 할 수있는 사용자 집합이 있고 "select * from [view]"를 실행하여 성능에 영향을 미치지 않게하려면 특정 기능에 대한 액세스 권한을 부여하면 필터 매개 변수를 제공 할 수 있습니다. 예를 들어 특정 인덱스 집합을 활용하십시오.
Jmoney38

35

불행히도 원하는 것을 달성하는 두 가지 방법이 있습니다.

원하는 매개 변수를 사용하고 쿼리 결과를 반환하는 테이블 값 사용자 정의 함수를 만들 수 있습니다

또는 거의 동일한 작업을 수행 할 수 있지만 사용자 정의 함수 대신 저장 프로 시저를 만들 수 있습니다.

예를 들어

저장 프로시 저는 다음과 같습니다

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
)

그냥 당신이있는 SP 옵션을 사용할 수 없습니다 것을 명심 SELECT쉽게 : 더 읽기 .
saastn

13

Mladen Prajdic가 말했듯이 당신은 할 수 없습니다. 뷰를 테이블 또는 테이블 조합에서 "정적 필터"로 생각하십시오. 예를 들어 뷰는 테이블을 결합 할 수 OrderCustomer당신의 행의 새로운 "테이블"을 얻을 수 있도록 Order고객의 이름과 고객 번호 (테이블의 조합)을 포함하는 새로운 컬럼과 함께. 또는 Order테이블 에서 처리되지 않은 주문 만 선택하는 뷰를 작성할 수 있습니다 (정적 필터).

그런 다음 다른 "정상"테이블에서 선택하는 것처럼보기에서 선택합니다. "정적되지 않은"모든 필터링은보기 외부에서 수행해야합니다 (예 : "밀러라는 고객의 모든 주문 가져 오기"또는 "처리되지 않은 주문 가져 오기) 12 월 24 일에 나왔습니다 ").


12

일반적으로 뷰는 매개 변수화되지 않습니다. 그러나 항상 일부 매개 변수를 주입 할 수 있습니다. 예를 들어 세션 컨텍스트 를 사용하는 경우 :

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에도 동일하게 적용됩니다 (물론 컨텍스트 함수의 구문이 다릅니다).


2
나는 이것이 매우 편리하다고 생각합니다. Java에서와 같이 웹 앱에 매개 변수를 전달하는 방법과 유사합니다.
8forty

1
쉽고 기능적인! 다시 말해 ... 완벽합니다! 감사합니다!
리카르도 바실 리치

나는 피곤했다. WHERE COUL 추가 = SESSION_CONTEXT (N'Ket '); 보기 결과 오류 'SESSION_CONTEXT'는 내장 함수 이름으로 인식되지 않습니다.
user123456

@ user123456 SQL Server 2016 이상 또는 Azure SQL 데이터베이스를 사용해야합니다
Lukasz Szozda

9

보기에 매개 변수가 필요한 이유는 무엇입니까? 당신은 WHERE절을 사용할 수 있습니다 .

create view v_emp as select * from emp ;

쿼리가 작업을 수행해야합니다.

select * from v_emp where emp_id=&eno;

11
경우 에 따라 뷰 WHERE대신 테이블에 대한 성능이 크게 향상 되는 WHERE경우가 있습니다.
Doug_Ivison

Doug가 말한 것은 다소 사실이지만 현대 데이터베이스는 뷰를 현명하게 '확장'하고 마치 전체 쿼리를 수동으로 수행하는 것과 동일한 결과로 효과적으로 끝나는 놀라운 작업을 수행 할 수 있습니다. 데이터베이스가 당신을 놀라게 할 수 있기 때문에 비효율적이라고 가정하지 마십시오-생성 된 쿼리 계획을보십시오. 뷰에 출력에 영향을주는 GROUP BY 절이있는 경우 주목할만한 예외입니다.이 경우 '외부'에서 WHERE를 수행 할 수 없습니다.
Simon_Weaver

8

저장 프로시 저나 함수없이 해킹하는 방법은 데이터베이스에 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

보기 요청에 사용하는 것이 끔찍합니다. 그러나 구성 / 단계 / 환경으로 이러한 숨겨진 매개 변수를 사용하는 것은 실제로 사용할 수 있습니다. 저에게는 플러스입니다.
TPAKTOPA



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

결과 집합을 얻을 수있는 관점은

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

5

내가 아는 것처럼 view는 select 명령과 같은 것일 수 있습니다. 예를 들어 다음과 같은 명령문에서이 선택에 매개 변수를 추가 할 수도 있습니다.

 WHERE  (exam_id = @var)

4

아니요, 뷰는 정적입니다. SQl 서버 버전에 따라 수행 할 수있는 한 가지 작업은 뷰를 인덱싱하는 것입니다.

예제 (한 테이블 만 쿼리)에서 인덱스 된 뷰는 단순히 인덱스가있는 테이블을 쿼리하는 데 도움이되지 않지만, 조인 조건이있는 테이블에서 많은 조인을 수행하면 인덱스 된 뷰가 성능을 크게 향상시킬 수 있습니다.


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
        )

그것이 도움이되기를 바랍니다.



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)

1

뷰를 실행하기 위해 우회 할 수 있습니다. SQL은 와인을 부르고 울지 만, 이렇게하고 실행하십시오! 저장할 수 없습니다.

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

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

1
그것은해야합니다 (PL / SQL과 T-SQL은 여러면에서 비슷합니다).하지만 알아내는 방법은 여러 가지가 있습니다.
Oleg Melnikov

0

아직 시도하지 않았다는 아이디어가 있습니다. 넌 할 수있어:

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)

매개 변수가 구성 테이블에 저장되고 변경됩니다.


2
응답의 정확성에 대해 의문이있는 경우 적어도 적절한 해결책 인지 확인하기 전에 게시하지 마십시오 . 그것이 말하듯이, 이것은 대답보다 더 많은 질문입니다.
chb

이 솔루션의 한 가지 문제점은 쿼리가 여러 세션에서 실행되는 경우 구성 테이블의 잘못된 데이터가 사용될 수 있다는 것입니다.
User1010

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.