Bisakah kita meneruskan parameter ke tampilan dalam SQL?


138

Bisakah kita meneruskan parameter ke tampilan di Microsoft SQL Server?

Saya mencoba dengan create viewcara berikut, tetapi tidak berhasil:

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

Tampilan adalah teks sql tersimpan dari kueri pemilihan. Parameter di luar diskusi. Saat kueri yang disimpan mengembalikan kolom tempat Anda ingin memfilter, Anda bisa melakukannya di kueri pemanggilan. Misalnya "SELECT * FROM v_emp WHERE emp_id =?"
Epicurist

2
@Epicurist Pernyataan Parameters are out of the discussionterlalu berani. Counterexample
Lukasz Szozda

Jawaban:


132

Seperti yang sudah dinyatakan Anda tidak bisa.

Solusi yang mungkin adalah dengan mengimplementasikan fungsi yang tersimpan, seperti:

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

Ini memungkinkan Anda untuk menggunakannya sebagai tampilan normal, dengan:

SELECT * FROM v_emp(10)

Apa perbedaan praktis antara ini dan pandangan? Bisakah Anda menetapkan izin pengguna untuk hanya mengakses fungsi ini?
MikeMurko

Di MySQL Anda menulis prosedur tersimpan dan memiliki pernyataan terakhir dalam prosedur menjadi resultset yang ingin Anda kembalikan.
bobobobo

dapatkah kita menggunakan permintaan itu tanpa masalah dari kode JDBC di java?
mounaim

@MikeMurko satu perbedaan penting adalah bahwa skema / metadata tentang kolom tampilan dapat ditanyakan jika itu adalah tampilan. Jika proc atau fungsinya tersimpan, maka saya kira basis data mungkin tidak dapat memberi Anda informasi itu.
nagu

Jika Anda memiliki satu set pengguna yang memiliki akses ke database Anda, dan Anda tidak ingin mereka menjalankan "pilih * dari [tampilan]" dan memengaruhi kinerja, Anda bisa memberikan akses ke fungsi-fungsi tertentu, yang akan MENDAPATKAN mereka untuk memberikan parameter filter bahwa, misalnya, memanfaatkan serangkaian indeks tertentu.
Jmoney38

35

Ada 2 cara untuk mencapai apa yang Anda inginkan sayangnya tidak dapat dilakukan menggunakan tampilan.

Anda bisa membuat tabel dengan nilai fungsi yang ditentukan pengguna yang mengambil parameter yang Anda inginkan dan mengembalikan hasil kueri

Atau Anda dapat melakukan hal yang hampir sama tetapi membuat prosedur tersimpan bukan fungsi yang ditentukan pengguna.

Sebagai contoh

prosedur yang tersimpan akan terlihat seperti

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

Atau fungsi yang ditentukan pengguna akan terlihat seperti

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

Ingatlah bahwa Anda tidak dapat menggunakan opsi SP dengan SELECTmudah: baca lebih lanjut .
saastn

13

Tidak, Anda tidak bisa, seperti kata Mladen Prajdic. Anggaplah view sebagai "filter statis" pada sebuah tabel atau kombinasi tabel. Misalnya: tampilan dapat menggabungkan tabel Orderdan Customerjadi Anda mendapatkan "tabel" baris Orderbaru bersama dengan kolom baru yang berisi nama pelanggan dan nomor pelanggan (kombinasi tabel). Atau Anda dapat membuat tampilan yang hanya memilih pesanan yang tidak diproses dari Ordertabel (filter statis).

Anda kemudian akan memilih dari tampilan seperti Anda akan memilih dari tabel "normal" lainnya - semua penyaringan "non-statis" harus dilakukan di luar tampilan (seperti "Dapatkan semua pesanan untuk pelanggan yang disebut Miller" atau "Dapatkan pesanan yang tidak diproses" yang datang pada 24 Desember ").


12

Biasanya tampilan tidak parameter. Tetapi Anda selalu bisa menyuntikkan beberapa parameter. Misalnya menggunakan konteks sesi :

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

Doa:

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

Dan satu lagi:

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

Demo DBFiddle

Hal yang sama berlaku untuk Oracle (tentu saja sintaks untuk fungsi konteks berbeda).


2
Saya pikir ini sangat berguna. Mirip dengan bagaimana parameter dapat diteruskan ke aplikasi web misalnya di Jawa.
8

1
mudah dan fungsional! Dengan kata lain ... sempurna! Terima kasih!
Riccardo Bassilichi

Saya lelah. Menambahkan WHERE COUL = SESSION_CONTEXT (N'Ket '); dalam tampilan menghasilkan Kesalahan 'SESSION_CONTEXT' bukan nama fungsi bawaan yang dikenali.
user123456

@ user123456 Anda harus menggunakan SQL Server 2016 dan di atasnya atau Azure SQL Database
Lukasz Szozda

9

Mengapa Anda memerlukan parameter dalam tampilan? Anda mungkin hanya menggunakan WHEREklausa.

create view v_emp as select * from emp ;

dan permintaan Anda harus melakukan pekerjaan:

select * from v_emp where emp_id=&eno;

11
Dalam beberapa kasus akan ada peningkatan kinerja yang besar, ketika itu WHEREuntuk tabel, bukan WHEREuntuk tampilan.
Doug_Ivison

Sementara apa yang dikatakan Doug agak benar, database modern dapat melakukan pekerjaan luar biasa untuk 'memperluas' tampilan secara cerdas dan secara efektif berakhir dengan hasil yang sama seperti jika Anda hanya melakukan kueri lengkap secara manual. Jadi jangan menganggap itu tidak efisien karena database mungkin akan mengejutkan Anda - lihat rencana permintaan yang dihasilkan. Pengecualian penting adalah jika tampilan memiliki klausa GROUP BY yang mempengaruhi output - dalam hal ini Anda tidak dapat melakukan WHERE dari 'luar'.
Simon_Weaver

8

Cara hacky untuk melakukannya tanpa prosedur atau fungsi tersimpan adalah dengan membuat tabel pengaturan di database Anda, dengan kolom Id, Param1, Param2, dll. Masukkan baris ke dalam tabel yang berisi nilai Id = 1, Param1 = 0, Param2 = 0, dll. Kemudian Anda dapat menambahkan gabungan ke tabel itu dalam tampilan Anda untuk membuat efek yang diinginkan, dan memperbarui tabel pengaturan sebelum menjalankan tampilan. Jika Anda memiliki beberapa pengguna yang memperbarui tabel pengaturan dan menjalankan tampilan secara bersamaan hal-hal bisa salah, tetapi sebaliknya itu akan berfungsi dengan baik. Sesuatu seperti:

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

akan mengerikan untuk menggunakannya untuk permintaan untuk melihat. Tapi ini benar-benar dapat digunakan, sebagai konfigurasi / tahap / lingkungan, untuk menggunakan parameter tersembunyi tersebut. Plus untuk saya untuk itu.
TPAKTOPA

6

tidak. jika Anda kemudian harus menggunakan fungsi yang ditentukan pengguna yang Anda dapat melewati parameter.


5

Tidak, tampilan tidak berbeda dengan SELECTing dari tabel.

Untuk melakukan apa yang Anda inginkan, gunakan fungsi yang ditentukan pengguna dengan nilai tabel dengan satu atau lebih parameter


5

Tampilan tidak lebih dari pernyataan 'SELECT' yang telah ditentukan sebelumnya. Jadi satu-satunya jawaban nyata adalah: Tidak, Anda tidak bisa.

Saya pikir apa yang benar-benar ingin Anda lakukan adalah membuat prosedur tersimpan, di mana pada prinsipnya Anda dapat menggunakan SQL yang valid untuk melakukan apa pun yang Anda inginkan, termasuk menerima parameter dan memilih data.

Sepertinya Anda benar-benar hanya perlu menambahkan klausa tempat ketika Anda memilih dari tampilan Anda, tetapi Anda tidak benar-benar memberikan detail yang cukup untuk memastikan.


5

kita bisa menulis prosedur tersimpan dengan parameter input dan kemudian menggunakan prosedur tersimpan itu untuk mendapatkan hasil yang ditetapkan dari tampilan. lihat contoh di bawah ini.

prosedur tersimpan adalah

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

dan tampilan dari mana kita bisa mendapatkan hasil adalah

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

Seperti yang saya tahu view bisa menjadi sesuatu seperti perintah pilih. Anda juga dapat menambahkan parameter ke pilih ini misalnya di mana pernyataan seperti ini:

 WHERE  (exam_id = @var)

4

Tidak, tampilan statis. Satu hal yang dapat Anda lakukan (tergantung pada versi server SQl) adalah mengindeks tampilan.

Dalam contoh Anda (hanya meminta satu tabel), tampilan yang diindeks tidak memiliki manfaat untuk hanya meminta tabel dengan indeks di atasnya, tetapi jika Anda melakukan banyak gabungan pada tabel dengan kondisi gabungan, tampilan yang diindeks dapat sangat meningkatkan kinerja.


4

Jika Anda tidak ingin menggunakan fungsi, Anda dapat menggunakan sesuatu seperti ini

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

Semoga ini bisa membantu


3

tidak, Anda dapat meneruskan parameter ke prosedur yang sedang dilihat


2

Berikut adalah opsi yang belum saya lihat:

Cukup tambahkan kolom yang ingin Anda batasi pada tampilan:

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

Anda dapat memotong hanya untuk menjalankan tampilan, SQL akan anggur dan menangis tetapi lakukan ini dan jalankan! Anda tidak bisa menabung.

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

1

Tampilan Anda dapat merujuk beberapa tabel eksternal yang berisi parameter Anda.

Seperti yang disebutkan lainnya, tampilan dalam SQL Server tidak dapat memiliki parameter input eksternal. Namun, Anda dapat dengan mudah memalsukan variabel dalam tampilan menggunakan CTE. Anda dapat menguji-menjalankannya di versi SQL Server Anda.

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

menghasilkan output:

status  name
12      dbo
0       db_accessadmin
0       db_securityadmin
0       db_ddladmin

juga 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

juga 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
Seharusnya (PL / SQL dan T-SQL serupa dalam banyak hal), tetapi ada lebih dari satu cara untuk mengetahuinya :) Cobalah.
Oleg Melnikov

0

Saya punya ide yang belum saya coba. Anda dapat melakukan:

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)

Parameter Anda akan disimpan dan diubah di tabel Config.


2
Jika Anda ragu tentang kebenaran jawaban, jangan posting sebelum Anda memverifikasi bahwa itu setidaknya solusi yang memadai . Seperti berdiri, ini lebih merupakan pertanyaan daripada jawaban.
chb

Satu masalah dengan solusi ini adalah bahwa jika kueri dijalankan dalam beberapa sesi, data yang salah dalam tabel konfigurasi mungkin digunakan
User1010

0

Saya menyadari tugas ini untuk kebutuhan saya sebagai berikut

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.