Chúng ta có thể truyền tham số cho một khung nhìn trong SQL không?


135

Chúng ta có thể truyền tham số cho chế độ xem trong Microsoft SQL Server không?

Tôi đã cố gắng create viewtheo cách sau, nhưng nó không hoạt động:

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

Một khung nhìn là một văn bản sql được lưu trữ của một truy vấn chọn. Các thông số được đưa ra khỏi cuộc thảo luận. Khi truy vấn được lưu trữ của bạn trả về cột mà bạn muốn lọc, bạn có thể thực hiện điều đó trong truy vấn gọi. Ví dụ: "CHỌN * TỪ v_emp WHERE emp_id =?"
Nhà sử học

2
@Epicurist Parameters are out of the discussionTuyên bố quá táo bạo.

Câu trả lời:


131

Như đã nêu bạn không thể.

Một giải pháp khả thi sẽ là thực hiện một chức năng được lưu trữ, như:

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

Điều này cho phép bạn sử dụng nó như một chế độ xem bình thường, với:

SELECT * FROM v_emp(10)

Sự khác biệt thực tế giữa điều này và một quan điểm là gì? Bạn có thể chỉ định quyền người dùng chỉ truy cập chức năng này?
MikeMurko

Trong MySQL, bạn viết một thủ tục được lưu trữ và có câu lệnh cuối cùng trong thủ tục là kết quả bạn muốn trả về.
bobobobo

chúng ta có thể sử dụng yêu cầu đó mà không có bất kỳ vấn đề nào từ mã JDBC trong java không?
mounaim

@MikeMurko một điểm khác biệt quan trọng là lược đồ / siêu dữ liệu về các cột của chế độ xem có thể được truy vấn nếu đó là chế độ xem. Nếu nó được lưu trữ hoặc một chức năng, thì tôi đoán cơ sở dữ liệu có thể không thể cung cấp cho bạn thông tin đó.
nagu

Nếu bạn có một nhóm người dùng có quyền truy cập vào cơ sở dữ liệu của bạn và bạn không muốn họ chạy "select * from [view]" và ảnh hưởng đến hiệu suất, bạn có thể cấp quyền truy cập vào một số chức năng, điều này sẽ buộc họ cung cấp các tham số bộ lọc rằng, ví dụ, tận dụng một bộ chỉ số nhất định.
Jmoney38

34

Có 2 cách để đạt được điều bạn muốn một cách đáng tiếc, không thể thực hiện được bằng cách sử dụng chế độ xem.

Bạn có thể tạo một hàm có giá trị do người dùng định nghĩa bảng lấy tham số bạn muốn và trả về kết quả truy vấn

Hoặc bạn có thể làm khá nhiều thứ tương tự nhưng tạo một thủ tục được lưu trữ thay vì hàm do người dùng xác định.

Ví dụ

thủ tục lưu trữ sẽ trông như thế nào

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

Hoặc chức năng do người dùng xác định sẽ trông như thế nào

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

Chỉ cần lưu ý rằng bạn không thể sử dụng tùy chọn SP một SELECTcách dễ dàng: đọc thêm .
saastn

13

Không, bạn không thể, như Mladen Prajdic nói. Hãy nghĩ về một khung nhìn như một "bộ lọc tĩnh" trên một bảng hoặc một tổ hợp các bảng. Ví dụ: một chế độ xem có thể kết hợp các bảng OrderCustomerdo đó bạn có được một "bảng" hàng Ordermới cùng với các cột mới chứa tên của khách hàng và số khách hàng (kết hợp các bảng). Hoặc bạn có thể tạo chế độ xem chỉ chọn các đơn đặt hàng chưa được xử lý từ Orderbảng (bộ lọc tĩnh).

Sau đó, bạn sẽ chọn từ chế độ xem như bạn sẽ chọn từ bất kỳ bảng "bình thường" nào khác - tất cả quá trình lọc "không tĩnh" phải được thực hiện ngoài chế độ xem (như "Nhận tất cả các đơn đặt hàng cho khách hàng được gọi là Miller" hoặc "Nhận đơn đặt hàng chưa xử lý đã đến vào ngày 24 tháng 12 ").


12

Thông thường các khung nhìn không được tham số hóa. Nhưng bạn luôn có thể tiêm một số thông số. Ví dụ: sử dụng bối cảnh phiên :

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

Cầu nguyện:

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

Và một cái khác:

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

Trình diễn DBFiddle

Điều tương tự cũng được áp dụng cho Oracle (tất nhiên cú pháp cho chức năng ngữ cảnh là khác nhau).


2
Tôi nghĩ rằng điều này là khá tiện dụng. Tương tự như cách các tham số có thể được truyền cho các ứng dụng web, ví dụ như trong Java.
8

1
dễ dàng và chức năng! Nói cách khác ... hoàn hảo! Cảm ơn bạn!
Riccardo Bassilichi

Tôi mệt mỏi. Thêm WHERE COUL = SESSION_CONTEXT (N'Ket '); trong kết quả xem trong Lỗi 'SESSION_CONTEXT' không phải là tên hàm tích hợp được công nhận.
user123456

@ user123456 Bạn phải sử dụng SQL Server 2016 trở lên hoặc Cơ sở dữ liệu SQL Azure
Lukasz Szozda

9

Tại sao bạn cần một tham số trong xem? Bạn chỉ có thể sử dụng WHEREmệnh đề.

create view v_emp as select * from emp ;

và truy vấn của bạn sẽ thực hiện công việc:

select * from v_emp where emp_id=&eno;

11
Trong một số trường hợp, sẽ có một cải tiến hiệu suất lớn, khi đó là WHEREcho bảng, thay vì WHEREcho chế độ xem.
Doug_Ivison

Mặc dù những gì Doug nói là hơi đúng, nhưng các cơ sở dữ liệu hiện đại có thể thực hiện một cách thông minh là 'mở rộng' một cách nhìn và kết thúc hiệu quả với cùng một kết quả như thể bạn chỉ thực hiện truy vấn đầy đủ theo cách thủ công. Vì vậy, đừng cho rằng nó sẽ không hiệu quả vì cơ sở dữ liệu có thể làm bạn ngạc nhiên - hãy nhìn vào kế hoạch truy vấn được tạo. Một ngoại lệ đáng chú ý sẽ là nếu chế độ xem có mệnh đề GROUP BY ảnh hưởng đến đầu ra - trong trường hợp đó bạn không thể thực hiện WHERE từ 'bên ngoài'.
Simon_Weaver

8

Một cách khó khăn để làm điều đó mà không có các thủ tục hoặc hàm được lưu trữ sẽ là tạo một bảng cài đặt trong cơ sở dữ liệu của bạn, với các cột Id, Param1, Param2, v.v. Chèn một hàng vào bảng đó chứa các giá trị Id = 1, Param1 = 0, Param2 = 0, v.v. Sau đó, bạn có thể thêm một liên kết vào bảng đó trong chế độ xem của mình để tạo hiệu ứng mong muốn và cập nhật bảng cài đặt trước khi chạy chế độ xem. Nếu bạn có nhiều người dùng cập nhật bảng cài đặt và chạy chế độ xem đồng thời, mọi thứ có thể bị lỗi, nhưng nếu không thì nó sẽ hoạt động tốt. Cái gì đó như:

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

nó sẽ là khủng khiếp để sử dụng nó cho một yêu cầu để xem. Nhưng nó thực sự có thể sử dụng được, như một cấu hình / giai đoạn / môi trường, để sử dụng các tham số ẩn như vậy. Một Plus cho tôi cho điều đó.
TPAKTOPA

6

Không. nếu sau đó bạn phải sử dụng hàm do người dùng xác định mà bạn có thể truyền tham số vào.



5

Một khung nhìn không có gì khác hơn là một tuyên bố 'CHỌN' được xác định trước. Vì vậy, câu trả lời thực sự duy nhất sẽ là: Không, bạn không thể.

Tôi nghĩ rằng những gì bạn thực sự muốn làm là tạo một thủ tục được lưu trữ, theo nguyên tắc bạn có thể sử dụng bất kỳ SQL hợp lệ nào để làm bất cứ điều gì bạn muốn, bao gồm chấp nhận tham số và chọn dữ liệu.

Có vẻ như bạn thực sự chỉ cần thêm một mệnh đề where khi bạn chọn từ chế độ xem của mình, nhưng bạn không thực sự cung cấp đủ chi tiết để chắc chắn.


5

chúng ta có thể viết một thủ tục được lưu trữ với các tham số đầu vào và sau đó sử dụng thủ tục được lưu trữ đó để lấy tập kết quả từ khung nhìn. xem ví dụ dưới đây.

thủ tục lưu trữ là

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

và khung nhìn từ đó chúng ta có thể nhận được tập kết quả là

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

Theo tôi biết, view có thể giống như lệnh select. Bạn cũng có thể thêm các tham số vào phần chọn này, ví dụ như trong đó các câu lệnh như thế này:

 WHERE  (exam_id = @var)

4

Không, một cái nhìn là tĩnh. Một điều bạn có thể làm (tùy thuộc vào phiên bản của máy chủ SQl) là lập chỉ mục một chế độ xem.

Trong ví dụ của bạn (chỉ truy vấn một bảng), chế độ xem được lập chỉ mục không có lợi khi chỉ truy vấn bảng có chỉ mục trên đó, nhưng nếu bạn thực hiện nhiều phép nối trên bảng có điều kiện nối, thì chế độ xem được lập chỉ mục có thể cải thiện hiệu suất rất nhiều.


4

Nếu bạn không muốn sử dụng một chức năng, bạn có thể sử dụng một cái gì đó như thế này

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

Hy vọng nó sẽ giúp


3

không, bạn có thể truyền tham số cho thủ tục trong khung nhìn


2

Đây là một tùy chọn tôi chưa thấy cho đến nay:

Chỉ cần thêm cột bạn muốn hạn chế vào chế độ xem:

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

Bạn có thể bỏ qua chỉ để chạy view, SQL sẽ khóc và khóc nhưng chỉ cần làm điều này và chạy nó! Bạn không thể tiết kiệm.

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

1

Khung nhìn của bạn có thể tham chiếu một số bảng bên ngoài có chứa các tham số của bạn.

Như những người khác đã đề cập, khung nhìn trong SQL Server không thể có các tham số đầu vào bên ngoài. Tuy nhiên, bạn có thể dễ dàng giả mạo một biến trong chế độ xem của mình bằng CTE. Bạn có thể chạy thử nó trong phiên bản SQL Server của bạn.

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

mang lại sản lượng:

status  name
12      dbo
0       db_accessadmin
0       db_securityadmin
0       db_ddladmin

cũng thông qua 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

cũng thông qua 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
Nó nên (PL / SQL và T-SQL giống nhau theo nhiều cách), nhưng có nhiều hơn một cách để tìm hiểu :) Hãy thử xem.
Oleg Melnikov

0

Tôi có một ý tưởng mà tôi chưa thử. Bạn có thể làm:

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)

Các tham số của bạn sẽ được lưu và thay đổi trong bảng Cấu hình.


2
Nếu bạn nghi ngờ về tính xác thực của phản hồi, đừng đăng nó trước khi bạn xác minh rằng đó ít nhất là một giải pháp thích hợp . Khi nó đứng, đây là một câu hỏi nhiều hơn là một câu trả lời.
chb

Một vấn đề với giải pháp này là nếu truy vấn đang được chạy trong nhiều phiên, dữ liệu sai trong bảng cấu hình có thể được sử dụng
User1010

0

Tôi nhận ra nhiệm vụ này cho nhu cầu của mình như sau

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.