Parametreleri SQL'de bir görünüme aktarabilir miyiz?


139

Microsoft SQL Server'da bir görünüme parametre aktarabilir miyiz?

create viewŞu şekilde denedim ama işe yaramıyor:

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

Görünüm, seçilen bir sorgunun depolanan sql metnidir. Parametreler tartışma dışı. Depolanan sorgunuz filtrelemek istediğiniz sütunu döndürdüğünde, bunu arama sorgusunda yapabilirsiniz. Ör. "SEÇİN * v_emp NEREDE emp_id =?"
Epikurist

2
@Epicurist Parameters are out of the discussionÇok cesur bir ifade. Karşı örnek
Lukasz Szozda

Yanıtlar:


132

Daha önce de belirtildiği gibi yapamazsınız.

Olası bir çözüm, aşağıdakiler gibi depolanmış bir işlevi uygulamak olabilir:

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

Bu, aşağıdakilerle normal bir görünüm olarak kullanmanıza olanak tanır:

SELECT * FROM v_emp(10)

Bununla bir görüş arasındaki pratik farklar nelerdir? Yalnızca bu işleve erişmek için kullanıcı izinleri atayabilir misiniz?
MikeMurko

MySQL'de bir saklı yordam yazarsınız ve yordamdaki son deyimin döndürülmesini istediğiniz sonuç kümesi olur.
bobobobo

Java'daki JDBC kodundan herhangi bir sorun olmadan bu isteği kullanabilir miyiz?
mounaim

@MikeMurko'nun önemli bir farkı, bir görünümün sütunlarıyla ilgili şema / meta verilerin, eğer bir görünümse sorgulanabilmesidir. Depolanan proc veya bir işlevi varsa, sanırım veritabanları size bu bilgiyi veremeyebilir.
nagu

Veritabanınıza erişimi olan bir dizi kullanıcınız varsa ve onların "[görünüm] içinden * seç" i çalıştırmasını ve performansı etkilemesini istemiyorsanız, belirli işlevlere erişim izni verebilirsiniz, bu da onları filtre parametreleri sağlamaya ZORLAR örneğin, belirli bir dizin (ler) kümesinden yararlanır.
Jmoney38

35

Ne yazık ki istediğinizi elde etmenin 2 yolu vardır ve hiçbiri bir görünüm kullanılarak yapılamaz.

İstediğiniz parametreyi alan ve bir sorgu sonucu döndüren tablo değerli kullanıcı tanımlı bir işlev oluşturabilirsiniz.

Veya hemen hemen aynı şeyi yapabilir, ancak kullanıcı tanımlı bir işlev yerine bir saklı yordam oluşturabilirsiniz.

Örneğin

saklı yordam şöyle görünür

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

Veya kullanıcı tanımlı işlev şöyle görünür

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

SP seçeneğini SELECTkolayca kullanamayacağınızı unutmayın : daha fazlasını okuyun .
saastn

13

Mladen Prajdic'in dediği gibi, yapamazsınız. Bir görünümü, bir tablo veya tabloların bir kombinasyonu üzerinde "statik filtre" olarak düşünün. Örneğin: bir görünüm tabloları birleştirebilir Orderve Customerböylece Ordermüşterinin adını ve müşteri numarasını (tabloların birleşimi) içeren yeni sütunların yanı sıra yeni bir satır "tablosu" elde edersiniz . Ya da Ordertablodan yalnızca işlenmemiş siparişleri seçen bir görünüm (statik filtre) oluşturabilirsiniz.

Ardından, görünümden, diğer "normal" tablodan seçeceğiniz gibi seçim yaparsınız - tüm "statik olmayan" filtreleme, görünümün dışında yapılmalıdır ("Miller adlı müşteriler için tüm siparişleri al" veya "İşlenmemiş siparişleri al" gibi) 24 Aralık'ta geldi ").


12

Normalde görünümler parametreleştirilmez. Ama her zaman bazı parametreleri enjekte edebilirsiniz. Örneğin, oturum bağlamını kullanmak :

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

çağırma:

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

Ve başka:

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

DBFiddle Demo

Aynısı Oracle için de geçerlidir (tabii ki bağlam işlevi sözdizimi farklıdır).


2
Bunun oldukça kullanışlı olduğunu düşünüyorum. Parametrelerin web uygulamalarına, örneğin Java'ya aktarılmasına benzer.
8

1
kolay ve işlevsel! Başka bir deyişle ... mükemmel! Teşekkür ederim!
Riccardo Bassilichi

Yorgunum. WHERE COUL = SESSION_CONTEXT (N'Ket ') ekleniyor; görünümde sonuçta Hata 'SESSION_CONTEXT' tanınan bir yerleşik işlev adı değil.
user123456

@ user123456 SQL Server 2016 ve üstü veya Azure SQL Veritabanı kullanmalısınız
Lukasz Szozda

9

Görünümde neden bir parametreye ihtiyacınız var? Sadece WHEREcümle kullanabilirsin .

create view v_emp as select * from emp ;

ve sorgunuz şu işi yapmalıdır:

select * from v_emp where emp_id=&eno;

11
Bazı durumlarda , görünüm için WHEREdeğil, tablo için olduğunda büyük bir performans artışı olacaktır WHERE.
Doug_Ivison

Doug'un söylediği biraz doğru olsa da, modern veritabanları, bir görünümü akıllıca "genişletme" ve sanki tam sorguyu manuel olarak yapacakmışsınız gibi etkili bir şekilde aynı sonuca ulaşma konusunda olağanüstü bir iş çıkarabilir. Bu nedenle, veritabanı sizi şaşırtabileceği için verimsiz olacağını düşünmeyin - oluşturulan sorgu planına bakın. Görüntünün çıktıyı etkileyen bir GROUP BY deyimine sahip olması dikkate değer bir istisna olabilir - bu durumda WHERE'yi 'dışarıdan' yapamazsınız.
Simon_Weaver

8

Bunu saklı yordamlar veya işlevler olmadan yapmanın karmaşık bir yolu, veritabanınızda Id, Param1, Param2 vb. Sütunlarla bir ayarlar tablosu oluşturmaktır. Bu tabloya Id = 1, Param1 = 0, Param2 değerlerini içeren bir satır ekleyin. = 0, vb. Ardından, istediğiniz efekti oluşturmak için görünümünüzde bu tabloya bir birleştirme ekleyebilir ve görünümü çalıştırmadan önce ayarlar tablosunu güncelleyebilirsiniz. Ayarlar tablosunu güncelleyen ve görünümü aynı anda çalıştıran birden fazla kullanıcınız varsa, işler ters gidebilir, ancak aksi takdirde iyi çalışması gerekir. Gibi bir şey:

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

görüntüleme isteği için kullanmak korkunç olurdu. Ancak bu tür gizli parametreleri kullanmak bir yapılandırma / aşama / ortam olarak gerçekten kullanılabilir. Bunun için benim için bir Artı.
TPAKTOPA

6

Hayır. daha sonra parametreleri geçirebileceğiniz kullanıcı tanımlı bir işlevi kullanmanız gerekiyorsa.



5

Görünüm, önceden tanımlanmış bir 'SELECT' ifadesinden başka bir şey değildir. Yani tek gerçek cevap şudur: Hayır, yapamazsınız.

Bence gerçekten yapmak istediğiniz şey, prensipte kabul parametreleri ve veri seçme dahil olmak üzere istediğiniz her şeyi yapmak için herhangi bir geçerli SQL'i kullanabileceğiniz bir saklı yordam oluşturmaktır.

Görünüşe göre gerçekten sadece kendi görünümünüzden seçim yaparken bir where cümlesi eklemeniz gerekiyor, ancak emin olmak için yeterli ayrıntı sağlamadınız.


5

girdi parametreleriyle bir saklı yordam yazabilir ve ardından bu saklı yordamı, görünümden bir sonuç kümesi almak için kullanabiliriz. aşağıdaki örneğe bakın.

saklı yordam

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

ve sonuç kümesini alabileceğimiz görünüm

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

Bildiğim gibi view, select komutu gibi bir şey olabilir. Bu seçime parametreler de ekleyebilirsiniz, örneğin aşağıdaki gibi ifadeler:

 WHERE  (exam_id = @var)

4

Hayır, görüş statiktir. Yapabileceğiniz bir şey (SQl sunucusunun sürümüne bağlı olarak) bir görünümü indekslemektir.

Örneğinizde (yalnızca bir tabloyu sorgulama), dizine alınmış bir görünümün üzerinde bir dizin bulunan tabloyu sorgulamanın bir yararı yoktur, ancak birleştirme koşullarına sahip tablolarda çok sayıda birleştirme yapıyorsanız, dizine alınmış bir görünüm performansı büyük ölçüde artırabilir.


4

Bir işlevi kullanmak istemiyorsanız, bunun gibi bir şey kullanabilirsiniz

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

Umarım yardımcı olur


3

hayır, parametreyi görünümdeki prosedüre geçiremezsiniz


2

İşte şimdiye kadar görmediğim bir seçenek:

Görünümü kısıtlamak istediğiniz sütunu eklemeniz yeterlidir:

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

Sadece görünümü çalıştırmak için bypass edebilirsiniz, SQL şarap içip ağlayacak ama sadece bunu yapın ve çalıştırın! Kurtaramazsınız.

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

1

Görünümünüz, parametrelerinizi içeren bazı harici tablolara başvurabilir.

Diğerlerinde belirtildiği gibi, SQL Server'daki görünümün harici girdi parametreleri olamaz. Ancak, CTE kullanarak görünümünüzdeki bir değişkeni kolayca taklit edebilirsiniz. SQL Server sürümünüzde test çalıştırabilirsiniz.

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

verimli çıktı:

status  name
12      dbo
0       db_accessadmin
0       db_securityadmin
0       db_ddladmin

ayrıca aracılığıyla 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

ayrıca aracılığıyla 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
Olması gerekir (PL / SQL ve T-SQL birçok yönden benzerdir), ancak öğrenmenin birden fazla yolu vardır :) Bir deneyin.
Oleg Melnikov

0

Henüz denemediğim bir fikrim var. Yapabilirsin:

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)

Parametreleriniz Yapılandırma tablosunda kaydedilecek ve değiştirilecektir.


2
Bir yanıtın doğruluğu konusunda şüpheleriniz varsa, en azından yeterli bir çözüm olduğunu doğrulamadan önce yanıtlamayın . Haliyle, bu bir cevaptan çok bir sorudur.
chb

Bu çözümle ilgili bir sorun, sorgu birden çok oturumda çalıştırılıyorsa, yapılandırma tablosundaki yanlış verilerin kullanılabileceğidir
Kullanıcı1010

0

İhtiyaçlarım için bu görevi şu şekilde gerçekleştirdim

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.