Чи можемо ми передати параметри перегляду в SQL?


138

Чи можемо ми передати параметр перегляду в 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 =?"
Епікуріст

2
@Epicurist Parameters are out of the discussionЗанадто сміливе твердження. Контрприклад
Лукаш Шозда

Відповіді:


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 Важливою відмінністю є те, що схему / метадані про стовпці подання можна запитувати, якщо це перегляд. Якщо його зберігається прок або функція, то, мабуть, бази даних можуть не змогти надати вам цю інформацію.
нагу

Якщо у вас є набір користувачів, які мають доступ до вашої бази даних, і ви не хочете, щоб вони працювали "select * from [view]" і впливали на продуктивність, ви можете надати доступ до певних функцій, що змусить їх надати параметри фільтра які, наприклад, використовують певний набір індексів.
Jmoney38

35

Є два способи досягти того, що ви бажаєте, на жаль, і неможливо зробити за допомогою перегляду.

Ви можете створити табличну функцію, визначену користувачем, яка приймає потрібний параметр і повертає результат запиту

Або ви можете зробити майже те саме, але створити збережену процедуру замість визначеної користувачем функції.

Наприклад

збережена процедура виглядала б так

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

Ні, ви не можете, як сказав Младен Прайдич. Подумайте про подання як "статичний фільтр" на столі або як комбінацію таблиць. Наприклад: представлення може поєднувати таблиці, 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
легко і функціонально! Іншими словами ... ідеально! Спасибі!
Ріккардо Бассілічі

Я втомився. Додавання WHERE COUL = SESSION_CONTEXT (N'Ket '); з огляду на результат, помилка "SESSION_CONTEXT" не є впізнаваною вбудованою функцією.
користувач123456

@ user123456 Вам потрібно використовувати SQL Server 2016 і новіші
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

Незважаючи на те, що Дуг говорить дещо правдиво, сучасні бази даних можуть виконати чудову роботу з розумного "розширення" перегляду та ефективного завершення з тим же результатом, як якщо б ви просто виконували повний запит вручну. Тому не вважайте, що це буде неефективно, оскільки база даних може вас здивувати - подивіться на створений план запитів. Помітним винятком буде, якщо в представленні є пункт 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

було б страшно використовувати його для запиту для перегляду. Але насправді корисно використовувати такі приховані параметри, як конфігурація / етап / середовище. Плюс для мене за це.
ТРАКТОПА

6

немає. якщо потім потрібно використовувати визначену користувачем функцію, до якої можна передати параметри.



5

Перегляд - це не що інше, як попередньо визначений вислів 'SELECT'. Тож єдиною реальною відповіддю було б: Ні, ви не можете.

Я думаю, що ви дійсно хочете зробити це створити збережену процедуру, де в принципі ви можете використовувати будь-який дійсний SQL, щоб робити все, що завгодно, включаючи прийняття параметрів і вибір даних.

Здається, ймовірно, що вам потрібно лише додати пункт де, коли ви вибираєте зі свого огляду, але ви дійсно не надали достатньо деталей, щоб бути впевненим.


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

Як я знаю, перегляд може бути чимось на зразок команди select. Ви також можете додати параметри до цього вибору, наприклад, де такі оператори:

 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
        )

Сподіваюся, це допоможе



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 багато в чому схожі), але існує більше ніж один спосіб дізнатися :) Спробуйте.
Олег Мельников

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
Якщо у вас є сумніви щодо правдивості відповіді, не публікуйте її, перш ніж переконатися, що це хоча б адекватне рішення. На сьогодні це питання більше, ніж відповідь.
чб

Однією з проблем цього рішення буде те, що якщо запит виконується протягом декількох сеансів, можуть використовуватися помилкові дані в конфігураційній таблиці
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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.