我有一个查询,其中包含日期和国家/地区名称,我想知道如何将其创建到函数中,以便日期率(即2000-01-01至2001-12-31之间)和国家/地区名称例如“德国”可以作为变量传递。
我创建了一个查询,但没有创建函数。
SELECT *
FROM Customers c
Join Orders o
On c.CustomerID = o.CustomerID
WHERE o.OrderDate BETWEEN '1990-01-01' AND '2017-01-01'
AND c.Country LIKE 'Germany'
是否可以为日期范围和国家/地区设置参数,以便可以在函数中传递这些参数?
答案 0 :(得分:3)
您可以创建一个inline table valued function,例如
CREATE FUNCTION dbo.GetCustomerOrders(@Country VARCHAR(255), @DateFrom DATE, @DateTo DATE)
RETURNS TABLE
AS
RETURN
( SELECT c.CustomerID,
o.OrderDate,
c.Country,
<Other Fields>
FROM dbo.Customers AS c
INNER JOIN dbo.Orders AS o
ON o.CustomerID = c.CustomerID
WHERE o.OrderDate >= @DateFrom
AND o.OrderDate <= @DateTo
AND c.Country = @Country
);
然后将其用作:
SELECT <columns>
FROM dbo.GetCustomerOrders('Germany', '19000101', '20170101') AS co;
或者,如果您需要使用另一个表作为参数源,则可以使用:
SELECT <columns>
FROM dbo.SomeOtherTable AS t
CROSS APPLY dbo.GetCustomerOrders(t.Country, t.StartDate, t.EndDate) AS co;
后一种用法很好地说明了为什么要封装简单选择的原因,表值函数比存储过程更好的主意。它虽然可重用,但用途更多。随着功能的查询定义扩展到外部查询中,它们的性能也往往会更好,因此您更有可能根据用例获得最佳执行计划。
我将BETWEEN
更改为>= AND <=
-尽管从语义上讲这是相同的,但我发现两者之间可能会引起问题,尤其是在查询日期时间列时。进一步阅读:What do BETWEEN and the devil have in common?。如果OrderDate
是日期时间列,您可能会发现以下更合适的内容:
WHERE o.OrderDate >= @DateFrom
AND o.OrderDate < DATEADD(DAY, 1, @DateTo)
我还明确列出了您的列(可以的话),因为您永远不要在生产代码中使用SELECT *
。进一步阅读:Bad habits to kick : using SELECT * / omitting the column list。我还包括dbo.
模式前缀,因为它是generally a good idea to do so(除非您有意将其保留,以便所引用的表根据登录名而有所不同,我怀疑您并非如此)
最后,由于您没有进行任何通配符或模式匹配,因此我将LIKE
更改为=
。
如果您想要存储过程,则语法为
CREATE PROCEDURE dbo.GetCustomerOrders (@Country VARCHAR(255), @DateFrom DATE, @DateTo DATE)
AS
BEGIN
SELECT c.CustomerID,
o.OrderDate,
c.Country,
<Other Fields>
FROM dbo.Customers AS c
INNER JOIN dbo.Orders AS o
ON o.CustomerID = c.CustomerID
WHERE o.OrderDate >= @DateFrom
AND o.OrderDate <= @DateTo
AND c.Country = @Country;
END
这将使用:
EXECUTE dbo.GetCustomerOrders('Germany', '19000101', '20170101');
但是如上所述,对于一个简单的选择,我不认为这提供了超过TVF的任何优势,只有劣势。
最后一点,我与SQL Blog或Aaron Bertrand没有关系,我并不是故意插入他的博客的负载,只是它们都非常相关。
答案 1 :(得分:0)
这将创建一个内联表值函数:
CREATE FUNCTION dbo.CustomerOrders (
@FromDate DATE,
@ToDate DATE,
@CountryLike VARCHAR(50))
RETURNS TABLE AS
RETURN
SELECT
*
FROM
Customers c
inner Join Orders o On c.CustomerID = o.CustomerID
WHERE
o.OrderDate BETWEEN @FromDate AND @ToDate AND
c.Country LIKE '%' + @CountryLike + '%'
请避免使用*
,而应替换为计划使用的实际列。还要注意,我在函数内部直接添加了两个通配符,因此您不必在国家名称上写%
(可以根据需要进行更改)。
您可以像以下方式使用它:
SELECT
C.*
FROM
dbo.CustomerOrders('2019-05-01', '2019-06-15', 'German') AS C