Possiamo passare i parametri a una vista in SQL?


138

È possibile passare un parametro a una vista in Microsoft SQL Server?

Ho provato a farlo create viewnel modo seguente, ma non funziona:

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

Una vista è un testo sql memorizzato di una query selezionata. I parametri sono fuori discussione. Quando la query memorizzata restituisce la colonna in cui si desidera filtrare, è possibile farlo nella query chiamante. Ad esempio "SELEZIONA * DA v_emp WHERE emp_id =?"
Epicurista,

2
@Epicurist Dichiarazione Parameters are out of the discussiontroppo audace. Controesempio
Lukasz Szozda,

Risposte:


132

Come già detto non puoi.

Una possibile soluzione sarebbe quella di implementare una funzione memorizzata, come:

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

Ciò ti consente di usarlo come una vista normale, con:

SELECT * FROM v_emp(10)

Quali sono le differenze pratiche tra questa e una visione? Puoi assegnare le autorizzazioni utente solo per accedere a questa funzione?
MikeMurko,

In MySQL scrivi una procedura memorizzata e l'ultima istruzione nella procedura corrisponde al set di risultati che desideri restituire.
bobobobo,

possiamo usare quella richiesta senza alcun problema dal codice JDBC in Java?
Mounaim,

@MikeMurko una differenza importante è che lo schema / i metadati relativi alle colonne di una vista possono essere interrogati se è una vista. Se è un proc memorizzato o una funzione, suppongo che i database potrebbero non essere in grado di darti tali informazioni.
nagu,

Se hai un gruppo di utenti che hanno accesso al tuo database e non vuoi che eseguano "seleziona * da [visualizza]" e influiscano sulle prestazioni, potresti concedere l'accesso a determinate funzioni, che FORZERANNO fornire parametri di filtro che, ad esempio, sfruttano un determinato insieme di indici.
Jmoney38,

35

Ci sono 2 modi per ottenere ciò che desideri sfortunatamente e nessuno dei due può essere fatto usando una vista.

È possibile creare una funzione definita dall'utente con valori di tabella che accetta il parametro desiderato e restituisce un risultato della query

Oppure puoi fare praticamente la stessa cosa ma creare una procedura memorizzata anziché una funzione definita dall'utente.

Per esempio

la procedura memorizzata sarebbe simile

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

Oppure la funzione definita dall'utente sarebbe simile

CREATE FUNCTION u_emp
(   
    @enoNumber INT
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT    
        * 
    FROM    
        emp 
    WHERE     
        emp_id=@enoNumber
)

Tieni presente che non puoi utilizzare l'opzione SP in modo SELECTsemplice: leggi di più .
Saastn

13

No, non puoi, come ha detto Mladen Prajdic. Pensa a una vista come a "filtro statico" su una tabella o su una combinazione di tabelle. Ad esempio: una vista può combinare tabelle Ordere Customerquindi si ottiene una nuova "tabella" di righe Orderinsieme a nuove colonne contenenti il ​​nome del cliente e il numero del cliente (combinazione di tabelle). In alternativa, è possibile creare una vista che seleziona solo gli ordini non elaborati dalla Ordertabella (filtro statico).

Quindi selezioneresti dalla vista come faresti da qualsiasi altra tabella "normale" - tutti i filtri "non statici" devono essere eseguiti al di fuori della vista (come "Ricevi tutti gli ordini per i clienti chiamati Miller" o "Ricevi ordini non elaborati che è arrivato il 24 dicembre ").


12

Normalmente le viste non sono parametrizzate. Ma potresti sempre iniettare alcuni parametri. Ad esempio utilizzando il contesto di sessione :

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

Invocazione:

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

E un altro:

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

DBFiddle Demo

Lo stesso vale per Oracle (ovviamente la sintassi per la funzione di contesto è diversa).


2
Penso che sia abbastanza utile. Simile a come i parametri possono essere passati alle app Web, ad esempio in Java.
8forty

1
facile e funzionale! In altre parole ... perfetto! Grazie!
Riccardo Bassilichi,

Sono stanco Aggiunta di WHERE COUL = SESSION_CONTEXT (N'Ket '); in vista risultato nell'errore 'SESSION_CONTEXT' non è un nome di funzione incorporata riconosciuto.
user123456

@ user123456 Devi usare SQL Server 2016 e versioni successive o Database SQL di Azure
Lukasz Szozda

9

Perché hai bisogno di un parametro in vista? Potresti semplicemente usare la WHEREclausola.

create view v_emp as select * from emp ;

e la tua query dovrebbe fare il lavoro:

select * from v_emp where emp_id=&eno;

11
In alcuni casi ci sarà un grande miglioramento delle prestazioni, quando è un WHEREper la tabella, anziché un WHEREper la vista.
Doug_Ivison,

Mentre quello che dice Doug è in qualche modo vero, i database moderni possono fare un lavoro straordinario "espandendo" in modo intelligente una vista e finendo efficacemente con lo stesso risultato come se dovessi semplicemente eseguire la query completa manualmente. Quindi non dare per scontato che sarà inefficiente perché il database potrebbe sorprenderti - guarda il piano di query generato. Un'eccezione notevole sarebbe se la vista ha una clausola GROUP BY che influenza l'output, nel qual caso non è possibile eseguire WHERE dall'esterno.
Simon_Weaver

8

Un modo complicato per farlo senza procedure o funzioni memorizzate sarebbe quello di creare una tabella delle impostazioni nel database, con colonne Id, Param1, Param2, ecc. Inserire una riga in quella tabella contenente i valori Id = 1, Param1 = 0, Param2 = 0, ecc. Quindi è possibile aggiungere un join a quella tabella nella vista per creare l'effetto desiderato e aggiornare la tabella delle impostazioni prima di eseguire la vista. Se hai più utenti che aggiornano la tabella delle impostazioni ed eseguono la vista contemporaneamente, le cose potrebbero andare male, ma altrimenti dovrebbe funzionare correttamente. Qualcosa di simile a:

CREATE VIEW v_emp 
AS 
SELECT      * 
FROM        emp E
INNER JOIN  settings S
ON          S.Id = 1 AND E.emp_id = S.Param1

sarebbe terribile usarlo per una richiesta di visualizzazione. Ma è davvero utilizzabile, come configurazione / stage / ambiente, utilizzare tali parametri nascosti. Un vantaggio per me per quello.
TPAKTOPA,

6

no. se è quindi necessario utilizzare una funzione definita dall'utente a cui è possibile passare i parametri.



5

Una vista non è altro che un'istruzione "SELECT" predeterminata. Quindi l'unica vera risposta sarebbe: No, non puoi.

Penso che ciò che vuoi davvero fare sia creare una procedura memorizzata, in cui in linea di principio puoi usare qualsiasi SQL valido per fare quello che vuoi, inclusi i parametri di accettazione e selezione dei dati.

Sembra probabile che tu debba davvero solo aggiungere una clausola where quando selezioni dal tuo punto di vista, ma in realtà non hai fornito abbastanza dettagli per esserne sicuro.


5

possiamo scrivere una procedura memorizzata con parametri di input e quindi utilizzare quella procedura memorizzata per ottenere un set di risultati dalla vista. vedi esempio sotto.

la procedura memorizzata è

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 la vista da cui possiamo ottenere il set di risultati è

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

Come so, view può essere qualcosa come il comando select. È inoltre possibile aggiungere parametri a questa selezione, ad esempio in cui istruzioni come questa:

 WHERE  (exam_id = @var)

4

No, una vista è statica. Una cosa che puoi fare (a seconda della versione del server SQl) è indicizzare una vista.

Nel tuo esempio (interrogare solo una tabella), una vista indicizzata non ha alcun vantaggio nel interrogare semplicemente la tabella con un indice su di essa, ma se stai facendo molti join su tabelle con condizioni di join, una vista indicizzata può migliorare notevolmente le prestazioni.


4

Se non vuoi usare una funzione, puoi usare qualcosa del genere

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

Spero che possa essere d'aiuto


3

no è possibile passare il parametro alla procedura in vista


2

Ecco un'opzione che non ho visto finora:

Aggiungi semplicemente la colonna che desideri limitare alla vista:

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

Puoi ignorare solo per eseguire la vista, SQL emetterà vino e piangerà, ma basta farlo ed eseguirlo! Non puoi salvare.

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

1

La tua vista può fare riferimento ad alcune tabelle esterne contenenti i tuoi parametri.

Come altri hanno già detto, la vista in SQL Server non può avere parametri di input esterni. Tuttavia, puoi facilmente falsificare una variabile nella tua vista usando CTE. È possibile testarlo nella versione di 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

rendimento produttivo:

status  name
12      dbo
0       db_accessadmin
0       db_securityadmin
0       db_ddladmin

anche 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

anche 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

1
Dovrebbe (PL / SQL e T-SQL sono simili in molti modi), ma c'è più di un modo per scoprirlo :) Provalo.
Oleg Melnikov,

0

Ho un'idea che non ho ancora provato. Tu puoi fare:

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)

I parametri verranno salvati e modificati nella tabella di configurazione.


2
Se hai dubbi sulla veridicità di una risposta, non pubblicarla prima di aver verificato che si tratta almeno di una soluzione adeguata . Allo stato attuale, questa è più una domanda che una risposta.
CHB

Un problema con questa soluzione sarà che se la query viene eseguita in più sessioni potrebbero essere utilizzati i dati errati nella tabella di configurazione
User1010

0

Ho realizzato questo compito per le mie esigenze come segue

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.