Czy możemy przekazać parametr do widoku w Microsoft SQL Server?
Próbowałem create view
w następujący sposób, ale to nie działa:
create or replace view v_emp(eno number) as select * from emp where emp_id=&eno;
Czy możemy przekazać parametr do widoku w Microsoft SQL Server?
Próbowałem create view
w następujący sposób, ale to nie działa:
create or replace view v_emp(eno number) as select * from emp where emp_id=&eno;
Parameters are out of the discussion
Zbyt odważne stwierdzenie. Counterexample
Odpowiedzi:
Jak już wspomniano, nie możesz.
Możliwym rozwiązaniem byłoby zaimplementowanie przechowywanej funkcji, takiej jak:
CREATE FUNCTION v_emp (@pintEno INT)
RETURNS TABLE
AS
RETURN
SELECT * FROM emp WHERE emp_id=@pintEno;
Pozwala to używać go jako normalnego widoku, z:
SELECT * FROM v_emp(10)
Niestety, istnieją 2 sposoby osiągnięcia tego, co chcesz, ale nie można tego zrobić za pomocą widoku.
Możesz utworzyć funkcję zdefiniowaną przez użytkownika z wartościami tabeli, która przyjmuje żądany parametr i zwraca wynik zapytania
Lub możesz zrobić prawie to samo, ale utworzyć procedurę składowaną zamiast funkcji zdefiniowanej przez użytkownika.
Na przykład
jak wyglądałaby procedura składowana
CREATE PROCEDURE s_emp
(
@enoNumber INT
)
AS
SELECT
*
FROM
emp
WHERE
emp_id=@enoNumber
Albo jak wyglądałaby funkcja zdefiniowana przez użytkownika
CREATE FUNCTION u_emp
(
@enoNumber INT
)
RETURNS TABLE
AS
RETURN
(
SELECT
*
FROM
emp
WHERE
emp_id=@enoNumber
)
SELECT
: przeczytaj więcej .
Nie, nie możesz, jak powiedział Mladen Prajdic. Pomyśl o widoku jako o „filtrze statycznym” tabeli lub kombinacji tabel. Na przykład: widok może łączyć tabele Order
i Customer
tak pojawi się nowy „stół” z wierszy Order
wraz z nowymi kolumnami zawierającymi nazwę klienta i numer klienta (połączenie tabel). Możesz też utworzyć widok, który wybiera tylko nieprzetworzone zamówienia z Order
tabeli (filtr statyczny).
Następnie wybierzesz z widoku, tak jak w przypadku każdej innej „normalnej” tabeli - wszystkie „niestatyczne” filtrowanie należy wykonać poza widokiem (np. „Pobierz wszystkie zamówienia dla klientów o nazwie Miller” lub „Otrzymuj nieprzetworzone zamówienia które nadeszło 24 grudnia ”).
Zwykle widoki nie są sparametryzowane. Ale zawsze możesz wprowadzić jakieś parametry. Na przykład używając kontekstu sesji :
CREATE VIEW my_view
AS
SELECT *
FROM tab
WHERE num = SESSION_CONTEXT(N'my_num');
Wezwanie:
EXEC sp_set_session_context 'my_num', 1;
SELECT * FROM my_view;
I kolejny:
EXEC sp_set_session_context 'my_num', 2;
SELECT * FROM my_view;
To samo dotyczy Oracle (oczywiście składnia funkcji kontekstu jest inna).
Dlaczego potrzebujesz widoku parametru? Możesz po prostu użyć WHERE
klauzuli.
create view v_emp as select * from emp ;
a twoje zapytanie powinno załatwić sprawę:
select * from v_emp where emp_id=&eno;
WHERE
dla tabeli, zamiast WHERE
dla widoku.
Hackim sposobem na zrobienie tego bez procedur składowanych lub funkcji byłoby utworzenie tabeli ustawień w bazie danych z kolumnami Id, Param1, Param2 itd. Wstaw wiersz do tej tabeli zawierający wartości Id = 1, Param1 = 0, Param2 = 0 itd. Następnie możesz dodać sprzężenie do tej tabeli w swoim widoku, aby uzyskać pożądany efekt, i zaktualizować tabelę ustawień przed uruchomieniem widoku. Jeśli masz wielu użytkowników aktualizujących tabelę ustawień i uruchamiających widok jednocześnie, rzeczy mogą pójść nie tak, ale poza tym powinno działać poprawnie. Coś jak:
CREATE VIEW v_emp
AS
SELECT *
FROM emp E
INNER JOIN settings S
ON S.Id = 1 AND E.emp_id = S.Param1
Nie. jeśli musisz użyć funkcji zdefiniowanej przez użytkownika, do której możesz przekazać parametry.
Nie, odpytywanie widoku nie różni się od wyboru z tabeli.
Aby zrobić to, co chcesz, użyj funkcji zdefiniowanej przez użytkownika z wartościami przechowywanymi w tabeli z co najmniej jednym parametrem
Widok to nic innego jak predefiniowana instrukcja „SELECT”. Tak więc jedyną prawdziwą odpowiedzią byłoby: Nie, nie możesz.
Myślę, że to, co naprawdę chcesz zrobić, to utworzyć procedurę składowaną, w której w zasadzie możesz użyć dowolnego prawidłowego kodu SQL, aby zrobić, co chcesz, w tym zaakceptować parametry i wybrać dane.
Wydaje się prawdopodobne, że naprawdę wystarczy dodać klauzulę WHERE tylko podczas wybierania z widoku, ale tak naprawdę nie podałeś wystarczająco dużo szczegółów, aby mieć pewność.
możemy napisać procedurę składowaną z parametrami wejściowymi, a następnie użyć tej procedury składowanej, aby uzyskać zestaw wyników z widoku. patrz przykład poniżej.
procedura składowana to
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
a widok, z którego możemy uzyskać zbiór wyników, to
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%')
Jak wiem, widok może być czymś w rodzaju polecenia wyboru. Możesz również dodać parametry do tego wyboru, na przykład w przypadku takich instrukcji:
WHERE (exam_id = @var)
Nie, widok jest statyczny. Jedną rzeczą, którą możesz zrobić (w zależności od wersji serwera SQl), jest zindeksowanie widoku.
W Twoim przykładzie (odpytywanie tylko jednej tabeli) widok indeksowany nie daje korzyści z prostego wysyłania zapytań do tabeli z indeksem, ale jeśli wykonujesz wiele sprzężeń w tabelach z warunkami łączenia, widok indeksowany może znacznie poprawić wydajność.
Jeśli nie chcesz używać funkcji, możesz użyć czegoś takiego
-- 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
)
Mam nadzieję, że to pomoże
Oto opcja, której do tej pory nie widziałem:
Po prostu dodaj kolumnę, którą chcesz ograniczyć do widoku:
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)
Możesz ominąć tylko po to, aby uruchomić widok, SQL będzie płakać i płakać, ale po prostu zrób to i uruchom! Nie możesz uratować.
create or replace view v_emp(eno number) as select * from emp where (emp_id = @Parameter1);
Twój widok może odnosić się do zewnętrznej tabeli zawierającej twoje parametry.
Jak wspominali inni, widok w SQL Server nie może mieć zewnętrznych parametrów wejściowych. Możesz jednak łatwo sfałszować zmienną w swoim widoku za pomocą CTE. Możesz go przetestować w swojej wersji 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
wydajność:
status name
12 dbo
0 db_accessadmin
0 db_securityadmin
0 db_ddladmin
również za pośrednictwem 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
również za pośrednictwem 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
Mam pomysł, którego jeszcze nie próbowałem. Możesz to zrobić:
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)
Twoje parametry zostaną zapisane i zmienione w tabeli konfiguracji.
Zrealizowałem to zadanie dla moich potrzeb w następujący sposób
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