Можем ли мы передать параметры в представление в SQL?


138

Можем ли мы передать параметр в представление в Microsoft SQL Server?

Пытался сделать create viewтак, но не получается:

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

Представление - это сохраненный sql-текст запроса выбора. Параметры вне обсуждения. Когда ваш сохраненный запрос возвращает столбец, в котором вы хотите выполнить фильтрацию, вы можете сделать это в вызывающем запросе. Например, "ВЫБРАТЬ * ИЗ v_emp WHERE emp_id =?"
Epicurist

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 06

можем ли мы без проблем использовать этот запрос из кода JDBC в java?
mounaim

@MikeMurko одно важное отличие состоит в том, что можно запросить схему / метаданные о столбцах представления, если это представление. Если это хранимая процедура или функция, я думаю, базы данных могут не предоставить вам эту информацию.
nagu

Если у вас есть группа пользователей, у которых есть доступ к вашей базе данных, и вы не хотите, чтобы они выполняли команду «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 Demo

То же самое применимо и к Oracle (конечно, синтаксис контекстной функции другой).


2
Думаю, это очень удобно. Подобно тому, как параметры могут быть переданы в веб-приложения, например, в Java.
8forty

1
легко и функционально! Другими словами ... отлично! Спасибо!
Riccardo Bassilichi

Я устал. Добавление WHERE COUL = SESSION_CONTEXT (N'Ket '); при просмотре результат ошибки «SESSION_CONTEXT» не является распознанным именем встроенной функции.
user123456 08

@ user123456 Вы должны использовать SQL Server 2016 и более поздние версии или базу данных SQL Azure
Лукаш Шозда,

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

было бы ужасно использовать его для запроса на просмотр. Но действительно можно использовать такие скрытые параметры в качестве конфигурации / этапа / среды. Плюс для меня за это.
TPAKTOPA

6

нет. если вы должны затем использовать определяемую пользователем функцию, в которую вы можете передавать параметры.



5

Представление - это не что иное, как предопределенный оператор SELECT. Итак, единственный реальный ответ: нет, нельзя.

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

Кажется вероятным, что вам действительно нужно добавить предложение where только при выборе из своего представления, но вы на самом деле не предоставили достаточно деталей, чтобы быть уверенным.


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:

 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 во многом похожи), но есть несколько способов выяснить это :) Попробуйте.
Олег Мельников

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)

Ваши параметры будут сохранены и изменены в таблице конфигурации.


2
Если вы сомневаетесь в правдивости ответа, не публикуйте его, пока не убедитесь, что это по крайней мере адекватное решение. В нынешнем виде это больше вопрос, чем ответ.
chb 03

Одна из проблем с этим решением будет заключаться в том, что если запрос выполняется в нескольких сеансах, могут использоваться неправильные данные в таблице конфигурации.
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.