Können wir Parameter an eine Ansicht in SQL übergeben?


135

Können wir einen Parameter an eine Ansicht in Microsoft SQL Server übergeben?

Ich habe es auf create viewfolgende Weise versucht , aber es funktioniert nicht:

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

Eine Ansicht ist ein gespeicherter SQL-Text einer ausgewählten Abfrage. Parameter sind nicht in der Diskussion. Wenn Ihre gespeicherte Abfrage die Spalte zurückgibt, nach der Sie filtern möchten, können Sie dies in der aufrufenden Abfrage tun. ZB "SELECT * FROM v_emp WHERE emp_id =?"
Epikurist

2
@Epicurist Parameters are out of the discussionZu kühne Aussage. Gegenbeispiel
Lukasz Szozda

Antworten:


131

Wie schon gesagt, kannst du nicht.

Eine mögliche Lösung wäre die Implementierung einer gespeicherten Funktion wie:

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

Auf diese Weise können Sie es als normale Ansicht verwenden, mit:

SELECT * FROM v_emp(10)

Was sind die praktischen Unterschiede zwischen dieser und einer Ansicht? Können Sie Benutzerberechtigungen zuweisen, um nur auf diese Funktion zuzugreifen?
Mike Murko

In MySQL schreiben Sie eine gespeicherte Prozedur und lassen die letzte Anweisung in der Prozedur die Ergebnismenge sein, die Sie zurückgeben möchten.
Bobobobo

Können wir diese Anfrage ohne Probleme aus JDBC-Code in Java verwenden?
Montag,

@ MikeMurko Ein wichtiger Unterschied besteht darin, dass das Schema / die Metadaten zu den Spalten einer Ansicht abgefragt werden können, wenn es sich um eine Ansicht handelt. Wenn es sich um einen gespeicherten Prozess oder eine Funktion handelt, können Datenbanken Ihnen diese Informationen möglicherweise nicht geben.
Nagu

Wenn Sie eine Gruppe von Benutzern haben, die Zugriff auf Ihre Datenbank haben und nicht möchten, dass sie "select * from [view]" ausführen und die Leistung beeinträchtigen, können Sie bestimmten Funktionen Zugriff gewähren, wodurch sie gezwungen werden, Filterparameter bereitzustellen die zum Beispiel einen bestimmten Satz von Indizes nutzen.
Jmoney38

34

Es gibt zwei Möglichkeiten, um das zu erreichen, was Sie leider wollen, und beide können nicht mit einer Ansicht ausgeführt werden.

Sie können entweder eine benutzerdefinierte Funktion mit Tabellenwert erstellen, die den gewünschten Parameter verwendet und ein Abfrageergebnis zurückgibt

Oder Sie können so ziemlich dasselbe tun, aber anstelle einer benutzerdefinierten Funktion eine gespeicherte Prozedur erstellen.

Beispielsweise

Die gespeicherte Prozedur würde so aussehen

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

Oder die benutzerdefinierte Funktion würde so aussehen

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

Denken Sie daran, dass Sie die SP-Option nicht SELECTeinfach verwenden können: Lesen Sie mehr .
Saastn

13

Nein, das kannst du nicht, wie Mladen Prajdic sagte. Stellen Sie sich eine Ansicht als "statischen Filter" für eine Tabelle oder eine Kombination von Tabellen vor. Zum Beispiel: eine Ansicht können Tabellen kombinieren Orderund Customerso eine neue „Tabelle“ Zeilen aus erhalten Orderzusammen mit neuen Spalten den Namen des Kunden und die Kundennummer (Kombination von Tabellen) enthält. Oder Sie erstellen eine Ansicht, in der nur unverarbeitete Aufträge aus der OrderTabelle ausgewählt werden (statischer Filter).

Sie würden dann aus der Ansicht auswählen, wie Sie es aus einer anderen "normalen" Tabelle auswählen würden - alle "nicht statischen" Filter müssen außerhalb der Ansicht durchgeführt werden (z. B. "Alle Bestellungen für Kunden mit dem Namen Miller abrufen" oder "Unverarbeitete Bestellungen abrufen" das kam am 24. Dezember ").


12

Normalerweise werden Ansichten nicht parametrisiert. Sie können jedoch immer einige Parameter einfügen. Beispiel: Verwenden des Sitzungskontexts :

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

Aufruf:

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

Und ein anderer:

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

DBFiddle Demo

Gleiches gilt für Oracle (natürlich ist die Syntax für die Kontextfunktion unterschiedlich).


2
Ich finde das ziemlich praktisch. Ähnlich wie Parameter an Webanwendungen übergeben werden können, z. B. in Java.
8forty

1
einfach und funktional! Mit anderen Worten ... perfekt! Danke!
Riccardo Bassilichi

Ich bin müde Hinzufügen von WHERE COUL = SESSION_CONTEXT (N'Ket '); In der Ansicht Ergebnis in Fehler 'SESSION_CONTEXT' ist kein erkannter integrierter Funktionsname.
user123456

@ user123456 Sie müssen SQL Server 2016 und höher oder Azure SQL Database
Lukasz Szozda

9

Warum benötigen Sie einen Parameter in der Ansicht? Sie könnten einfach eine WHEREKlausel verwenden.

create view v_emp as select * from emp ;

und Ihre Anfrage sollte den Job machen:

select * from v_emp where emp_id=&eno;

11
In einigen Fällen wird es eine große Leistungsverbesserung geben, wenn es sich um eine WHERETabelle statt um eine WHEREAnsicht handelt.
Doug_Ivison

Während das, was Doug sagt, etwas wahr ist, können moderne Datenbanken eine bemerkenswerte Arbeit leisten, indem sie eine Ansicht intelligent "erweitern" und effektiv das gleiche Ergebnis erzielen, als ob Sie nur die vollständige Abfrage manuell durchführen würden. Gehen Sie also nicht davon aus, dass dies ineffizient ist, da die Datenbank Sie möglicherweise überrascht. Sehen Sie sich den generierten Abfrageplan an. Eine bemerkenswerte Ausnahme wäre, wenn die Ansicht eine GROUP BY-Klausel enthält, die sich auf die Ausgabe auswirkt. In diesem Fall können Sie das WHERE nicht von außen ausführen.
Simon_Weaver

8

Eine hackige Möglichkeit, dies ohne gespeicherte Prozeduren oder Funktionen zu tun, besteht darin, eine Einstellungstabelle in Ihrer Datenbank mit den Spalten Id, Param1, Param2 usw. zu erstellen. Fügen Sie eine Zeile in diese Tabelle ein, die die Werte Id = 1, Param1 = 0, Param2 enthält = 0 usw. Anschließend können Sie dieser Tabelle in Ihrer Ansicht einen Join hinzufügen, um den gewünschten Effekt zu erzielen, und die Einstellungstabelle aktualisieren, bevor Sie die Ansicht ausführen. Wenn mehrere Benutzer die Einstellungstabelle aktualisieren und die Ansicht gleichzeitig ausführen, kann ein Fehler auftreten. Andernfalls sollte dies in Ordnung sein. Etwas wie:

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

Es wäre schrecklich, es für eine Anfrage zum Anzeigen zu verwenden. Aber es ist wirklich nützlich, als Konfiguration / Bühne / Umgebung solche versteckten Parameter zu verwenden. Ein Plus für mich dafür.
TPAKTOPA

6

Nein. Wenn Sie dann eine benutzerdefinierte Funktion verwenden müssen, an die Sie Parameter übergeben können.



5

Eine Ansicht ist nichts anderes als eine vordefinierte 'SELECT'-Anweisung. Die einzig wahre Antwort wäre also: Nein, das kannst du nicht.

Ich denke, was Sie wirklich tun möchten, ist eine gespeicherte Prozedur zu erstellen, in der Sie im Prinzip jede gültige SQL verwenden können, um zu tun, was Sie wollen, einschließlich der Annahme von Parametern und der Auswahl von Daten.

Es ist wahrscheinlich, dass Sie wirklich nur eine where-Klausel hinzufügen müssen, wenn Sie aus Ihrer Ansicht auswählen, aber Sie haben nicht wirklich genug Details angegeben, um sicherzugehen.


5

Wir können eine gespeicherte Prozedur mit Eingabeparametern schreiben und diese gespeicherte Prozedur dann verwenden, um eine Ergebnismenge aus der Ansicht abzurufen. siehe Beispiel unten.

Die gespeicherte Prozedur ist

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

und die Ansicht, aus der wir die Ergebnismenge erhalten können, ist

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

Wie ich weiß, kann die Ansicht so etwas wie ein Auswahlbefehl sein. Sie können dieser Auswahl auch Parameter hinzufügen, z. B. in folgenden Anweisungen:

 WHERE  (exam_id = @var)

4

Nein, eine Ansicht ist statisch. Sie können (abhängig von der Version des SQl-Servers) eine Ansicht indizieren.

In Ihrem Beispiel (nur eine Tabelle abfragen) hat eine indizierte Ansicht keinen Vorteil darin, die Tabelle einfach mit einem Index abzufragen. Wenn Sie jedoch viele Verknüpfungen für Tabellen mit Verknüpfungsbedingungen durchführen, kann eine indizierte Ansicht die Leistung erheblich verbessern.


4

Wenn Sie keine Funktion verwenden möchten, können Sie so etwas verwenden

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

Hoffe es wird helfen


3

Nein, Sie können den Parameter an die angezeigte Prozedur übergeben


2

Hier ist eine Option, die ich bisher noch nicht gesehen habe:

Fügen Sie einfach die Spalte, die Sie einschränken möchten, zur Ansicht hinzu:

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

Sie können umgehen, nur um die Ansicht auszuführen, SQL wird Wein und Weinen, aber tun Sie dies einfach und führen Sie es aus! Du kannst nicht retten.

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

1

Ihre Ansicht kann auf eine externe Tabelle verweisen, die Ihre Parameter enthält.

Wie bereits erwähnt, kann die Ansicht in SQL Server keine externen Eingabeparameter enthalten. Mit CTE können Sie jedoch leicht eine Variable in Ihrer Ansicht vortäuschen. Sie können es in Ihrer Version von SQL Server testen.

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

Ausbeute:

status  name
12      dbo
0       db_accessadmin
0       db_securityadmin
0       db_ddladmin

auch über 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

auch über 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
Es sollte (PL / SQL und T-SQL sind in vielerlei Hinsicht ähnlich), aber es gibt mehr als einen Weg, dies herauszufinden :) Probieren Sie es aus.
Oleg Melnikov

0

Ich habe eine Idee, die ich noch nicht ausprobiert habe. Du kannst tun:

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)

Ihre Parameter werden in der Config-Tabelle gespeichert und geändert.


2
Wenn Sie Zweifel an der Richtigkeit einer Antwort haben, veröffentlichen Sie sie nicht, bevor Sie überprüft haben, ob es sich zumindest um eine angemessene Lösung handelt. So wie es aussieht, ist dies eher eine Frage als eine Antwort.
chb

Ein Problem bei dieser Lösung besteht darin, dass bei Ausführung der Abfrage in mehreren Sitzungen möglicherweise die falschen Daten in der Konfigurationstabelle verwendet werden
User1010

0

Ich habe diese Aufgabe für meine Bedürfnisse wie folgt realisiert

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.