เราสามารถส่งผ่านพารามิเตอร์ไปยังมุมมองใน SQL ได้หรือไม่?


139

เราสามารถส่งพารามิเตอร์ไปยังมุมมองใน Microsoft SQL Server ได้หรือไม่

ฉันพยายามcreate viewทำตามวิธีต่อไปนี้ แต่ไม่ได้ผล:

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

มุมมองคือข้อความ sql ที่จัดเก็บไว้ของคิวรีแบบเลือก พารามิเตอร์ไม่อยู่ในการอภิปราย เมื่อคิวรีที่จัดเก็บของคุณส่งกลับคอลัมน์ที่คุณต้องการกรองด้วยคุณสามารถทำได้ในคิวรีการโทร เช่น "SELECT * FROM v_emp WHERE emp_id =?"
Epicurist

2
@Epicurist Parameters are out of the discussionงบหนาเกินไป ตัวอย่างตัวอย่าง
Lukasz Szozda

คำตอบ:


132

ตามที่ระบุไว้แล้วคุณทำไม่ได้

ทางออกที่เป็นไปได้คือการใช้ฟังก์ชันที่จัดเก็บเช่น:

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

สิ่งนี้ช่วยให้คุณใช้เป็นมุมมองปกติโดยมี:

SELECT * FROM v_emp(10)

อะไรคือความแตกต่างในทางปฏิบัติระหว่างสิ่งนี้กับมุมมอง? คุณสามารถกำหนดสิทธิ์ผู้ใช้เพื่อเข้าถึงฟังก์ชันนี้ได้หรือไม่?
MikeMurko

ใน MySQL คุณเขียนโพรซีเดอร์ที่เก็บไว้และมีคำสั่งสุดท้ายในโพรซีเดอร์คือผลลัพธ์ที่คุณต้องการส่งคืน
bobobobo

เราสามารถใช้คำขอนั้นโดยไม่มีปัญหาจากรหัส JDBC ใน java ได้หรือไม่
mounaim

@MikeMurko ข้อแตกต่างที่สำคัญประการหนึ่งคือสคีมา / ข้อมูลเมตาเกี่ยวกับคอลัมน์ของมุมมองสามารถสอบถามได้หากเป็นข้อมูลพร็อพเพอร์ตี้ หากจัดเก็บ proc หรือฟังก์ชันฉันเดาว่าฐานข้อมูลอาจไม่สามารถให้ข้อมูลนั้นแก่คุณได้
nagu

หากคุณมีกลุ่มผู้ใช้ที่สามารถเข้าถึงฐานข้อมูลของคุณและไม่ต้องการให้พวกเขาเรียกใช้ "เลือก * จาก [ดู]" และส่งผลกระทบต่อประสิทธิภาพคุณสามารถให้สิทธิ์การเข้าถึงฟังก์ชันบางอย่างซึ่งจะบังคับให้พวกเขาระบุพารามิเตอร์ตัวกรอง ยกตัวอย่างเช่นใช้ประโยชน์จากดัชนีชุดหนึ่ง
Jmoney38

35

มี 2 ​​วิธีในการบรรลุสิ่งที่คุณต้องการโดยไม่ได้ตั้งใจและไม่สามารถทำได้โดยใช้มุมมอง

คุณสามารถสร้างฟังก์ชันที่กำหนดโดยผู้ใช้ที่มีมูลค่าตารางซึ่งรับพารามิเตอร์ที่คุณต้องการและส่งคืนผลลัพธ์การสืบค้น

หรือคุณสามารถทำสิ่งเดียวกันได้ แต่สร้างกระบวนงานที่เก็บไว้แทนฟังก์ชันที่ผู้ใช้กำหนดเอง

ตัวอย่างเช่น

ขั้นตอนการจัดเก็บจะมีลักษณะดังนี้

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

หรือฟังก์ชันที่ผู้ใช้กำหนดจะมีลักษณะดังนี้

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

เพิ่งทราบว่าคุณไม่สามารถใช้ตัวเลือก SP ในSELECTได้อย่างง่ายดาย: อ่านรายละเอียดเพิ่มเติม
saastn

13

ไม่คุณทำไม่ได้อย่างที่ Mladen Prajdic กล่าว คิดว่ามุมมองเป็น "ตัวกรองแบบคงที่" บนโต๊ะหรือทั้งตาราง ตัวอย่างเช่น: มุมมองที่อาจรวมตารางOrderและCustomerเพื่อให้คุณได้รับใหม่ "ตาราง" ของแถวจากOrderพร้อมกับคอลัมน์ใหม่ที่มีชื่อลูกค้าและจำนวนลูกค้า (การรวมกันของตาราง) หรือคุณอาจสร้างมุมมองที่เลือกเฉพาะคำสั่งซื้อที่ยังไม่ได้ประมวลผลจากOrderตาราง (ตัวกรองแบบคงที่)

จากนั้นคุณจะเลือกจากมุมมองเช่นเดียวกับที่คุณเลือกจากตาราง "ปกติ" อื่น ๆ - การกรองแบบ "ไม่คงที่" ทั้งหมดจะต้องทำนอกมุมมอง (เช่น "รับคำสั่งซื้อทั้งหมดสำหรับลูกค้าที่เรียกว่ามิลเลอร์" หรือ "รับคำสั่งซื้อที่ยังไม่ได้ดำเนินการ ที่เข้ามาในวันที่ 24 ธันวาคม ")


12

โดยปกติมุมมองจะไม่ถูกกำหนดพารามิเตอร์ แต่คุณสามารถฉีดพารามิเตอร์บางอย่างได้เสมอ ตัวอย่างเช่นการใช้บริบทเซสชัน :

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

ภาวนา:

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

เเละอีกอย่าง:

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

การสาธิต DBFiddle

เช่นเดียวกับ Oracle (แน่นอนว่าไวยากรณ์สำหรับฟังก์ชันบริบทแตกต่างกัน)


2
ฉันคิดว่ามันค่อนข้างมีประโยชน์ คล้ายกับวิธีการส่งผ่านพารามิเตอร์ไปยังเว็บแอปเช่นใน Java
8

1
ใช้งานง่าย! กล่าวอีกนัยหนึ่ง ... สมบูรณ์แบบ! ขอบคุณ!
Riccardo Bassilichi

ฉันเหนื่อย. การเพิ่ม WHERE COUL = SESSION_CONTEXT (N'Ket '); ในมุมมองผลลัพธ์ข้อผิดพลาด "SESSION_CONTEXT" ไม่ใช่ชื่อฟังก์ชันในตัวที่รู้จัก
user123456

@ user123456 คุณต้องใช้ SQL Server 2016 ขึ้นไปหรือ Azure SQL Database
Lukasz Szozda

9

เหตุใดคุณจึงต้องมีพารามิเตอร์ในมุมมอง คุณอาจใช้WHEREประโยค

create view v_emp as select * from emp ;

และคำถามของคุณควรทำงาน:

select * from v_emp where emp_id=&eno;

11
ในบางกรณีจะมีการปรับปรุงประสิทธิภาพครั้งใหญ่เมื่อเป็นWHEREตารางแทนที่จะเป็นWHEREมุมมอง
Doug_Ivison

แม้ว่าสิ่งที่ Doug พูดจะเป็นความจริง แต่ฐานข้อมูลสมัยใหม่สามารถทำงานได้อย่างยอดเยี่ยมในการ 'ขยาย' มุมมองอย่างชาญฉลาดและลงเอยด้วยผลลัพธ์เดียวกันอย่างมีประสิทธิภาพราวกับว่าคุณเพียงแค่ทำแบบสอบถามแบบเต็มด้วยตนเอง ดังนั้นอย่าคิดว่ามันจะไม่มีประสิทธิภาพเพราะฐานข้อมูลอาจทำให้คุณประหลาดใจ - ดูแผนการสืบค้นที่สร้างขึ้น ข้อยกเว้นที่น่าสังเกตคือหากมุมมองมีคำสั่ง GROUP BY ที่มีผลต่อเอาต์พุตซึ่งในกรณีนี้คุณไม่สามารถทำ WHERE จาก "ภายนอก" ได้
Simon_Weaver

8

วิธีแฮ็คที่ทำได้โดยไม่ต้องจัดเก็บโพรซีเดอร์หรือฟังก์ชันคือการสร้างตารางการตั้งค่าในฐานข้อมูลของคุณโดยมีคอลัมน์ Id, Param1, Param2 และอื่น ๆ แทรกแถวลงในตารางที่มีค่า Id = 1, Param1 = 0, Param2 = 0 เป็นต้นจากนั้นคุณสามารถเพิ่มการเข้าร่วมในตารางนั้นในมุมมองของคุณเพื่อสร้างเอฟเฟกต์ที่ต้องการและอัปเดตตารางการตั้งค่าก่อนที่จะเรียกใช้มุมมอง หากคุณมีผู้ใช้หลายคนอัปเดตตารางการตั้งค่าและเรียกใช้มุมมองพร้อมกันสิ่งต่างๆอาจผิดพลาดได้ แต่อย่างอื่นก็ควรจะใช้ได้ สิ่งที่ต้องการ:

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

มันแย่มากที่จะใช้เพื่อขอดู แต่มันใช้งานได้จริงในฐานะคอนฟิกูเรชัน / สเตจ / สภาพแวดล้อมเพื่อใช้พารามิเตอร์ที่ซ่อนอยู่ดังกล่าว บวกสำหรับฉันสำหรับสิ่งนั้น
TPAKTOPA

6

ไม่ ถ้าคุณต้องใช้ฟังก์ชันที่ผู้ใช้กำหนดซึ่งคุณสามารถส่งผ่านพารามิเตอร์ไปได้


5

ไม่มุมมองจะถูกสอบถามไม่ต่างจากการเลือกจากตาราง

ในการทำสิ่งที่คุณต้องการให้ใช้ฟังก์ชันที่กำหนดโดยผู้ใช้ที่มีมูลค่าตารางโดยมีพารามิเตอร์อย่างน้อยหนึ่งพารามิเตอร์


5

มุมมองไม่มีอะไรมากไปกว่าคำสั่ง 'SELECT' ที่กำหนดไว้ล่วงหน้า ดังนั้นคำตอบเดียวที่แท้จริงคือไม่คุณทำไม่ได้

ฉันคิดว่าสิ่งที่คุณต้องการทำจริงๆคือสร้างโพรซีเดอร์ที่เก็บไว้ซึ่งโดยหลักการแล้วคุณสามารถใช้ SQL ที่ถูกต้องเพื่อทำอะไรก็ได้ที่คุณต้องการรวมถึงยอมรับพารามิเตอร์และเลือกข้อมูล

ดูเหมือนว่าคุณจะต้องเพิ่ม where clause เมื่อคุณเลือกจากมุมมองของคุณเท่านั้น แต่คุณไม่ได้ให้รายละเอียดเพียงพอที่จะแน่ใจ


5

เราสามารถเขียนโพรซีเดอร์ที่จัดเก็บด้วยพารามิเตอร์อินพุตจากนั้นใช้โพรซีเดอร์ที่เก็บไว้เพื่อรับชุดผลลัพธ์จากมุมมอง ดูตัวอย่างด้านล่าง

ขั้นตอนการจัดเก็บคือ

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

และมุมมองที่เราจะได้ชุดผลลัพธ์คือ

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

อย่างที่ฉันรู้ว่ามุมมองสามารถเป็นได้เช่นเดียวกับคำสั่งเลือก นอกจากนี้คุณยังสามารถเพิ่มพารามิเตอร์ในการเลือกนี้ได้เช่นในกรณีที่คำสั่งเช่นนี้:

 WHERE  (exam_id = @var)

4

ไม่มุมมองเป็นแบบคงที่ สิ่งหนึ่งที่คุณสามารถทำได้ (ขึ้นอยู่กับเวอร์ชันของเซิร์ฟเวอร์ SQl) คือสร้างดัชนีมุมมอง

ในตัวอย่างของคุณ (การสืบค้นเพียงตารางเดียว) มุมมองที่จัดทำดัชนีไม่มีประโยชน์ที่จะเพียงแค่ค้นหาตารางโดยมีดัชนีอยู่ แต่ถ้าคุณทำการรวมตารางจำนวนมากที่มีเงื่อนไขการเข้าร่วมมุมมองที่จัดทำดัชนีจะช่วยปรับปรุงประสิทธิภาพได้อย่างมาก


4

หากคุณไม่ต้องการใช้ฟังก์ชันคุณสามารถใช้สิ่งนี้ได้

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

หวังว่ามันจะช่วยได้


3

คุณไม่สามารถส่งผ่านพารามิเตอร์ไปยังโพรซีเดอร์ในมุมมอง


2

นี่คือตัวเลือกที่ฉันไม่เคยเห็นมาก่อน:

เพียงเพิ่มคอลัมน์ที่คุณต้องการ จำกัด ในมุมมอง:

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

คุณสามารถข้ามเพียงเพื่อเรียกใช้มุมมอง SQL จะไวน์และร้องไห้ แต่เพียงแค่ทำสิ่งนี้และเรียกใช้! คุณไม่สามารถบันทึกได้

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

1

มุมมองของคุณสามารถอ้างอิงตารางภายนอกที่มีพารามิเตอร์ของคุณ

ตามที่กล่าวไว้มุมมองใน SQL Server ไม่สามารถมีพารามิเตอร์อินพุตภายนอกได้ อย่างไรก็ตามคุณสามารถปลอมตัวแปรในมุมมองของคุณโดยใช้ CTE คุณสามารถทดสอบรันได้ใน 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

ให้ผลผลิต:

status  name
12      dbo
0       db_accessadmin
0       db_securityadmin
0       db_ddladmin

ผ่านทาง 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

ผ่านทาง 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
ควร (PL / SQL และ T-SQL มีความคล้ายคลึงกันในหลาย ๆ ด้าน) แต่มีวิธีค้นหามากกว่าหนึ่งวิธี :) ลองดูสิ
Oleg Melnikov

0

ฉันมีความคิดที่ยังไม่ได้ลอง คุณทำได้:

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)

พารามิเตอร์ของคุณจะถูกบันทึกและเปลี่ยนแปลงในตาราง Config


2
หากคุณมีข้อสงสัยเกี่ยวกับความถูกต้องของคำตอบอย่าโพสต์ก่อนที่จะตรวจสอบว่าอย่างน้อยก็เป็นวิธีแก้ปัญหาที่เพียงพอ ตามที่กล่าวมานี่เป็นคำถามมากกว่าคำตอบ
chb

ปัญหาหนึ่งในการแก้ปัญหานี้คือหากมีการเรียกใช้แบบสอบถามในหลายเซสชันข้อมูลที่ไม่ถูกต้องในตารางการกำหนดค่าอาจถูกใช้
User1010

0

ฉันตระหนักถึงงานนี้สำหรับความต้องการของฉันดังนี้

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.