Podemos passar parâmetros para uma visualização no SQL?

138

Podemos passar um parâmetro para uma exibição no Microsoft SQL Server?

Eu tentei create viewda seguinte maneira, mas não funciona:

create or replace view v_emp(eno number) as select * from emp where emp_id=&eno;
arunachalam
fonte
Uma visualização é um texto sql armazenado de uma consulta selecionada. Os parâmetros estão fora de discussão. Quando sua consulta armazenada retorna a coluna na qual você deseja filtrar, você pode fazer isso na consulta de chamada. Por exemplo, "SELECT * FROM v_emp WHERE emp_id =?"
Epicurista 28/03
2
@ Epicurist Declaração Parameters are out of the discussionmuito ousada. Counterexample
Lukasz Szozda

Respostas:

132

Como já foi dito, você não pode.

Uma solução possível seria implementar uma função armazenada, como:

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

Isso permite que você o use como uma visualização normal, com:

SELECT * FROM v_emp(10)
Alex Bagnolini
fonte
Quais são as diferenças práticas entre isso e uma visão? Você pode atribuir permissões de usuário para acessar apenas esta função?
22412 MikeMurko
No MySQL, você escreve um procedimento armazenado e a última instrução do procedimento é o conjunto de resultados que você deseja retornar.
bobobobo
podemos usar essa solicitação sem nenhum problema do código JDBC em java?
Mounaim
@MikeMurko Uma diferença importante é que o esquema / metadados sobre as colunas de uma visualização podem ser consultados, se for uma visualização. Se seu proc armazenado ou uma função, acho que os bancos de dados podem não ser capazes de fornecer essas informações.
nagu 14/11/16
Se você possui um conjunto de usuários com acesso ao seu banco de dados e não deseja que eles executem "select * from [view]" e afetem o desempenho, você pode conceder acesso a determinadas funções, o que os forçaria a fornecer parâmetros de filtro que, por exemplo, aproveite um determinado conjunto de índices.
Jmoney38
35

Existem duas maneiras de conseguir o que você deseja, infelizmente, nem pode ser feito usando uma visualização.

Você pode criar uma função definida pelo usuário com valor de tabela que aceita o parâmetro desejado e retorna um resultado da consulta

Ou você pode fazer praticamente a mesma coisa, mas criar um procedimento armazenado em vez de uma função definida pelo usuário.

Por exemplo

o procedimento armazenado pareceria

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

Ou a função definida pelo usuário seria semelhante a

CREATE FUNCTION u_emp
(   
    @enoNumber INT
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT    
        * 
    FROM    
        emp 
    WHERE     
        emp_id=@enoNumber
)
Gavin
fonte
Lembre-se de que você não pode usar a opção SP SELECTfacilmente: leia mais .
saastn 11/03/19
13

Não, você não pode, como disse Mladen Prajdic. Pense em uma visualização como um "filtro estático" em uma tabela ou uma combinação de tabelas. Por exemplo: uma exibição pode combinar tabelas Ordere, Customerassim, você obtém uma nova "tabela" de linhas Orderjunto com novas colunas contendo o nome do cliente e o número do cliente (combinação de tabelas). Ou você pode criar uma exibição que selecione apenas pedidos não processados ​​da Ordertabela (filtro estático).

Você selecionaria a partir da visualização como selecionaria em qualquer outra tabela "normal" - toda a filtragem "não estática" deve ser feita fora da visualização (como "Obter todos os pedidos de clientes chamados Miller" ou "Obter pedidos não processados que chegou em 24 de dezembro ").

Thorsten Dittmar
fonte
12

Normalmente, as visualizações não são parametrizadas. Mas você sempre pode injetar alguns parâmetros. Por exemplo, usando o contexto da sessão :

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

Invocação:

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

E outro:

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

DBFiddle Demo

O mesmo se aplica ao Oracle (é claro que a sintaxe da função de contexto é diferente).

Lukasz Szozda
fonte
2
Eu acho que isso é bastante útil. Semelhante a como os parâmetros podem ser passados ​​para aplicativos da web, por exemplo, em Java.
8forty
1
fácil e funcional! Em outras palavras ... perfeito! Obrigado!
Riccardo Bassilichi 18/01/19
Eu cansei. Adicionando WHERE COUL = SESSION_CONTEXT (N'Ket '); no resultado da exibição no Erro 'SESSION_CONTEXT' não é um nome de função interno reconhecido.
user123456
@ user123456 Você tem que usar o SQL Server 2016 e acima ou banco de dados SQL Azure
Lukasz Szozda
9

Por que você precisa de um parâmetro em exibição? Você pode apenas usar a WHEREcláusula

create view v_emp as select * from emp ;

e sua consulta deve fazer o trabalho:

select * from v_emp where emp_id=&eno;
Mahesh
fonte
11
Em alguns casos, haverá uma grande melhoria no desempenho, quando for WHEREpara a tabela, em vez de WHEREpara a exibição.
Doug_Ivison
Embora o que Doug diga seja verdade, os bancos de dados modernos podem fazer um trabalho notável de 'expandir' uma exibição de maneira inteligente e efetivamente terminar com o mesmo resultado, como se você fizesse a consulta completa manualmente. Portanto, não assuma que será ineficiente porque o banco de dados pode surpreendê-lo - observe o plano de consulta gerado. Uma exceção notável seria se a exibição tiver uma cláusula GROUP BY que afeta a saída - nesse caso, você não poderá executar o WHERE a partir de 'fora'.
Simon_Weaver 7/11/19
8

Uma maneira hacky de fazê-lo sem procedimentos ou funções armazenadas seria criar uma tabela de configurações em seu banco de dados, com as colunas Id, Param1, Param2, etc. Insira uma linha nessa tabela contendo os valores Id = 1, Param1 = 0, Param2 = 0, etc. Em seguida, você pode adicionar uma junção a essa tabela na sua exibição para criar o efeito desejado e atualizar a tabela de configurações antes de executar a exibição. Se você tiver vários usuários atualizando a tabela de configurações e executando a exibição simultaneamente, as coisas podem dar errado, mas, caso contrário, deve funcionar bem. Algo como:

CREATE VIEW v_emp 
AS 
SELECT      * 
FROM        emp E
INNER JOIN  settings S
ON          S.Id = 1 AND E.emp_id = S.Param1
Bozonik
fonte
seria terrível usá-lo para um pedido de visualização. Mas é realmente útil, como configuração / estágio / ambiente, usar esses parâmetros ocultos. Uma vantagem para mim por isso.
TPAKTOPA
6

não. se você deve usar uma função definida pelo usuário para a qual você pode passar parâmetros.

Mladen Prajdic
fonte
5

Uma visualização nada mais é do que uma instrução 'SELECT' predefinida. Portanto, a única resposta real seria: Não, você não pode.

Eu acho que o que você realmente deseja fazer é criar um procedimento armazenado, onde, em princípio, você pode usar qualquer SQL válido para fazer o que quiser, incluindo aceitar parâmetros e selecionar dados.

Parece provável que você realmente só precise adicionar uma cláusula where quando selecionar a partir de sua exibição, mas não forneceu detalhes suficientes para ter certeza.

Kris
fonte
5

podemos escrever um procedimento armazenado com parâmetros de entrada e depois usá-lo para obter um conjunto de resultados da exibição. veja o exemplo abaixo.

o procedimento armazenado é

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

e a visão da qual podemos obter o conjunto de resultados é

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%')  
tomar sol
fonte
5

Como eu sei, a visualização pode ser algo como o comando select. Você também pode adicionar parâmetros a essa seleção, por exemplo, em instruções onde:

 WHERE  (exam_id = @var)
Reza Ameri
fonte
4

Não, uma visualização é estática. Uma coisa que você pode fazer (dependendo da versão do servidor SQl) é indexar uma exibição.

No seu exemplo (consultando apenas uma tabela), uma exibição indexada não tem nenhum benefício em simplesmente consultar a tabela com um índice, mas se você estiver fazendo muitas junções em tabelas com condições de junção, uma exibição indexada poderá melhorar bastante o desempenho.

John
fonte
4

Se você não quiser usar uma função, poderá usar algo como isto

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

Espero que ajude

Adnan Badar
fonte
3

não, você pode passar o parâmetro para o procedimento em vista

aicuxiao
fonte
2

Aqui está uma opção que eu não vi até agora:

Basta adicionar a coluna que você deseja restringir à exibição:

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)
FarajDaoud
fonte
1

Você pode ignorar apenas para executar a exibição, o SQL irá chorar, mas faça isso e execute-o! Você não pode salvar.

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

Sua visão pode fazer referência a alguma tabela externa que contém seus parâmetros.

Como outros mencionados, a exibição no SQL Server não pode ter parâmetros de entrada externos. No entanto, você pode facilmente falsificar uma variável em sua exibição usando o CTE. Você pode testá-lo na sua versão do 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

produzindo saída:

status  name
12      dbo
0       db_accessadmin
0       db_securityadmin
0       db_ddladmin

também 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

também 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
fonte
1
Deveria (PL / SQL e T-SQL são semelhantes em muitos aspectos), mas há mais de uma maneira de descobrir :) Faça uma tentativa.
Oleg Melnikov
0

Tenho uma ideia que ainda não tentei. Você pode fazer:

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)

Seus parâmetros serão salvos e alterados na tabela Config.

Emman
fonte
2
Se você tiver dúvidas sobre a veracidade de uma resposta, não a publique antes de verificar se é pelo menos uma solução adequada . Tal como está, isso é mais uma pergunta do que uma resposta.
chb
Um problema com esta solução será que, se a consulta estiver sendo executada em várias sessões, os dados incorretos na tabela de configuração poderão ser usados.
User1010
0

Eu realizei esta tarefa para minhas necessidades da seguinte maneira

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
fonte