Pouvons-nous passer des paramètres à une vue en SQL?


138

Pouvons-nous passer un paramètre à une vue dans Microsoft SQL Server?

J'ai essayé de create viewla manière suivante, mais cela ne fonctionne pas:

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

Une vue est un texte SQL stocké d'une requête de sélection. Les paramètres sont hors de la discussion. Lorsque votre requête stockée renvoie la colonne sur laquelle vous souhaitez filtrer, vous pouvez le faire dans la requête appelante. Par exemple, "SELECT * FROM v_emp WHERE emp_id =?"
Epicurist

2
@Epicurist Déclaration Parameters are out of the discussiontrop audacieuse. Counterexample
Lukasz Szozda

Réponses:


132

Comme déjà indiqué, vous ne pouvez pas.

Une solution possible serait d'implémenter une fonction stockée, comme:

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

Cela vous permet de l'utiliser comme une vue normale, avec:

SELECT * FROM v_emp(10)

Quelles sont les différences pratiques entre ceci et une vue? Pouvez-vous attribuer des autorisations utilisateur pour accéder uniquement à cette fonction?
MikeMurko

Dans MySQL, vous écrivez une procédure stockée et la dernière instruction de la procédure est le jeu de résultats que vous souhaitez renvoyer.
bobobobo

pouvons-nous utiliser cette demande sans aucun problème à partir du code JDBC en java?
mounaim

@MikeMurko une différence importante est que le schéma / les métadonnées concernant les colonnes d'une vue peuvent être interrogés s'il s'agit d'une vue. Si son proc stocké ou une fonction, alors je suppose que les bases de données ne pourront peut-être pas vous donner cette information.
nagu

Si vous avez un ensemble d'utilisateurs qui ont accès à votre base de données et que vous ne voulez pas qu'ils exécutent "select * from [view]" et qu'ils aient un impact sur les performances, vous pouvez accorder l'accès à certaines fonctions, ce qui les FORCERA à fournir des paramètres de filtre qui, par exemple, exploitent un certain ensemble d'index.
Jmoney38

35

Il existe deux façons de réaliser ce que vous voulez, malheureusement, aucune ne peut être réalisée avec une vue.

Vous pouvez créer une fonction définie par l'utilisateur à valeur de table qui prend le paramètre souhaité et renvoie un résultat de requête

Ou vous pouvez faire à peu près la même chose, mais créer une procédure stockée au lieu d'une fonction définie par l'utilisateur.

Par exemple

la procédure stockée ressemblerait à

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

Ou la fonction définie par l'utilisateur ressemblerait à

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

Gardez simplement à l'esprit que vous ne pouvez pas utiliser l'option SP SELECTfacilement: en savoir plus .
saastn

13

Non, vous ne pouvez pas, comme l'a dit Mladen Prajdic. Considérez une vue comme un «filtre statique» sur une table ou une combinaison de tables. Par exemple: une vue peut combiner des tables Orderet Customerainsi vous obtenez une nouvelle «table» de lignes Orderavec de nouvelles colonnes contenant le nom du client et le numéro de client (combinaison de tables). Ou vous pouvez créer une vue qui sélectionne uniquement les commandes non traitées de la Ordertable (filtre statique).

Vous choisiriez ensuite dans la vue comme vous le feriez dans n'importe quel autre tableau "normal" - tout filtrage "non statique" doit être effectué en dehors de la vue (comme "Obtenir toutes les commandes pour les clients appelés Miller" ou "Obtenir les commandes non traitées" qui est arrivé le 24 décembre ").


12

Normalement, les vues ne sont pas paramétrées. Mais vous pouvez toujours injecter des paramètres. Par exemple en utilisant le contexte de session :

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;

Et un autre:

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

Démo DBFiddle

Il en va de même pour Oracle (bien sûr, la syntaxe de la fonction contextuelle est différente).


2
Je pense que c'est assez pratique. Similaire à la façon dont les paramètres peuvent être transmis aux applications Web, par exemple en Java.
8forty

1
simple et fonctionnel! En d'autres termes ... parfait! Merci!
Riccardo Bassilichi

Je suis fatiguée. Ajout de WHERE COUL = SESSION_CONTEXT (N'Ket '); dans la vue, l'erreur "SESSION_CONTEXT" n'est pas un nom de fonction intégré reconnu.
user123456

@ user123456 Vous devez utiliser SQL Server 2016 et supérieur ou Azure SQL Database
Lukasz Szozda

9

Pourquoi avez-vous besoin d'un paramètre en vue? Vous pourriez simplement utiliser une WHEREclause.

create view v_emp as select * from emp ;

et votre requête devrait faire le travail:

select * from v_emp where emp_id=&eno;

11
Dans certains cas, il y aura une grande amélioration des performances, lorsqu'il s'agit d'un WHEREpour la table, au lieu d'un WHEREpour la vue.
Doug_Ivison

Bien que ce que dit Doug soit quelque peu vrai, les bases de données modernes peuvent faire un travail remarquable en `` développant '' intelligemment une vue et en aboutissant efficacement au même résultat que si vous deviez simplement faire la requête complète manuellement. Alors ne supposez pas que ce sera inefficace car la base de données peut vous surprendre - regardez le plan de requête généré. Une exception notable serait si la vue a une clause GROUP BY qui affecte la sortie - dans ce cas, vous ne pouvez pas faire le WHERE de «l'extérieur».
Simon_Weaver

8

Une manière piratée de le faire sans procédures ou fonctions stockées serait de créer une table de paramètres dans votre base de données, avec les colonnes Id, Param1, Param2, etc. Insérez une ligne dans cette table contenant les valeurs Id = 1, Param1 = 0, Param2 = 0, etc. Ensuite, vous pouvez ajouter une jointure à cette table dans votre vue pour créer l'effet souhaité et mettre à jour la table des paramètres avant d'exécuter la vue. Si plusieurs utilisateurs mettent à jour le tableau des paramètres et exécutent la vue simultanément, les choses peuvent mal tourner, mais sinon, cela devrait fonctionner correctement. Quelque chose comme:

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

ce serait terrible de l'utiliser pour une demande de visualisation. Mais c'est vraiment utilisable, en tant que configuration / étape / environnement, d'utiliser de tels paramètres cachés. Un plus pour moi pour ça.
TPAKTOPA

6

non. si vous devez ensuite utiliser une fonction définie par l'utilisateur à laquelle vous pouvez passer des paramètres.


5

Non, une vue n'est pas interrogée différemment de SELECT à partir d'une table.

Pour faire ce que vous voulez, utilisez une fonction définie par l' utilisateur table avec un ou plusieurs paramètres


5

Une vue n'est rien de plus qu'une instruction 'SELECT' prédéfinie. La seule vraie réponse serait donc: non, vous ne pouvez pas.

Je pense que ce que vous voulez vraiment faire est de créer une procédure stockée, où en principe vous pouvez utiliser n'importe quel SQL valide pour faire ce que vous voulez, y compris accepter des paramètres et sélectionner des données.

Il semble probable que vous n'ayez vraiment besoin d'ajouter une clause where que lorsque vous sélectionnez dans votre vue, mais vous n'avez pas vraiment fourni suffisamment de détails pour être sûr.


5

nous pouvons écrire une procédure stockée avec des paramètres d'entrée, puis utiliser cette procédure stockée pour obtenir un jeu de résultats à partir de la vue. voir l'exemple ci-dessous.

la procédure stockée est

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

et la vue à partir de laquelle nous pouvons obtenir le jeu de résultats est

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

Comme je le sais, la vue peut être quelque chose comme la commande select. Vous pouvez également ajouter des paramètres à cette sélection, par exemple dans des instructions where comme celle-ci:

 WHERE  (exam_id = @var)

4

Non, une vue est statique. Une chose que vous pouvez faire (selon la version du serveur SQl) est d'indexer une vue.

Dans votre exemple (interroger une seule table), une vue indexée n'a aucun avantage à simplement interroger la table avec un index dessus, mais si vous effectuez beaucoup de jointures sur des tables avec des conditions de jointure, une vue indexée peut grandement améliorer les performances.


4

Si vous ne souhaitez pas utiliser de fonction, vous pouvez utiliser quelque chose comme ça

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

J'espère que cela aidera


3

non vous pouvez passer le paramètre à la procédure en vue


2

Voici une option que je n'ai pas vue jusqu'à présent:

Ajoutez simplement la colonne que vous souhaitez restreindre à la vue:

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

Vous pouvez contourner juste pour exécuter la vue, SQL va crier et pleurer, mais faites-le et exécutez-le! Vous ne pouvez pas sauver.

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

1

Votre vue peut référencer une table externe contenant vos paramètres.

Comme d'autres l'ont mentionné, la vue dans SQL Server ne peut pas avoir de paramètres d'entrée externes. Cependant, vous pouvez facilement simuler une variable dans votre vue en utilisant CTE. Vous pouvez l'exécuter en test dans votre version de 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

produisant une sortie:

status  name
12      dbo
0       db_accessadmin
0       db_securityadmin
0       db_ddladmin

aussi 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

aussi 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
Cela devrait (PL / SQL et T-SQL sont similaires à bien des égards), mais il y a plus d'une façon de le savoir :) Essayez-le.
Oleg Melnikov

0

J'ai une idée que je n'ai pas encore essayée. Tu peux faire:

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)

Vos paramètres seront enregistrés et modifiés dans le tableau de configuration.


2
Si vous avez des doutes sur la véracité d'une réponse, ne la postez pas avant de vérifier qu'il s'agit au moins d' une solution adéquate . Dans l'état actuel des choses, c'est plus une question qu'une réponse.
chb

Un problème avec cette solution sera que si la requête est exécutée dans plusieurs sessions, les mauvaises données dans la table de configuration pourraient être utilisées
User1010

0

J'ai réalisé cette tâche pour mes besoins comme suit

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.