我一直在阅读有关避免在 WHERE 子句中使用函数的内容(因为它们经常必须使用扫描并且通常效率不高)。
我有一个 SP,可以根据客户在过去几天是否过生日来计算他们的年龄。
我正在努力将生日的计算从 where 子句转移到 select 语句中。这是当前的 SP。
CREATE PROCEDURE dbo.SP_CalculateAge (
@LastNDays int
) AS
UPDATE Customers
SET CustomerAge = DATEDIFF (yy, CustomerBirthDate, GETDATE ())
WHERE DATEADD (yy, DATEDIFF (yy, CustomerBirthDate, GETDATE ()), CustomerBirthDate) BETWEEN
DATEADD (dd, ISNULL (@LastNDays, -4), GETDATE ()) AND GETDATE ();
我对它所创造的时代感到满意。看看其他建议,我还可以通过执行以下操作来计算 AGE
SELECT DATEDIFF(year, CustomerBirthDate, getdate()) + CASE WHEN (DATEADD(year,DATEDIFF(year, CustomerBirthDate, getdate()) , CustomerBirthDate) > getdate()) THEN - 1 ELSE 0 END
from customers'
我的问题是,我现在不确定可以将用于搜索生日是否发生在过去 4 天内的部分放在哪里。我只能在 WHERE 子句中想到它,而不能在 SELECT 中想到它。
BETWEEN
DATEADD (dd, ISNULL (@LastNDays, -4), GETDATE ()) AND GETDATE ();
我假设我需要某种 CASE 语句或 IF。
目前,每个客户每次都会运行此操作...我想专门针对过去 N 天内生日的客户运行它。
CREATE TABLE [dbo].[Customers](
[CustomerID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[CustomerFirstName] [varchar](30) NOT NULL,
[CustomerBirthDate] [datetime] NULL,
[CustomerAge] [smallint] NULL
CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED
(
[CustomerID] ASC
)
)
CREATE NONCLUSTERED INDEX [ix_Customers_CustomerBirthDate] ON [dbo].[Customers]
(
[CustomerBirthDate] ASC
)
INCLUDE([CustomerID],[CustomerFirstName],[CustomerAge])
INSERT INTO [dbo].[Customers] ([CustomerFirstName],[CustomerBirthDate])
VALUES('Stephen', '2000-11-14'),
('Sarah', '1980-11-15'),
('Zoe', '1965-01-01')
基于此,如果我们要运行代码,它会将 CustomerAge 添加到 Stephen 和 Sarah,但将 Zoe 保留为 NULL。
如有任何建议,我们将不胜感激。
亲切的问候, 斯蒂芬
我认为上面给出的答案大多是有效的,但是,我个人非常不喜欢计算列,无论它们是直接在表定义中定义的,还是通过作业来维护的。我不喜欢前者,因为它们会造成尴尬的索引 - 为了索引计算列,您需要将其持久化,这意味着每当您更新表中的值时都需要重新计算该列,并且我不喜欢后者,因为它们依赖工作。
如果您的目标只是让您的年龄计算与您所询问的
WHERE
子句配合使用,我认为这应该适合您,并且也应该可以正确索引:
DECLARE @LastNDays INT = 4
CREATE TABLE #Customers
(
[CustomerID] [int] IDENTITY PRIMARY KEY,
[CustomerFirstName] [varchar] (30) NOT NULL,
[CustomerBirthDate] [datetime] NULL
)
INSERT INTO #Customers ([CustomerFirstName], [CustomerBirthDate])
VALUES
('Stephen', '2000-11-14'),
('Sarah', '1980-11-17'),
('Zoe', '1965-01-01')
SELECT
CustomerFirstName,
CustomerBirthDate,
DATEDIFF(YY, CustomerBirthDate, GETDATE()) + (CASE WHEN DATEADD(YY, DATEDIFF(YY, CustomerBirthDate, GETDATE()), CustomerBirthDate) > GETDATE() THEN -1 ELSE 0 END) AS CustomerAge,
DATEDIFF(DD, GETDATE(), DATEADD(YY, DATEDIFF(YY, CustomerBirthDate, GETDATE()), CustomerBirthDate)) AS DaysSinceLastBirthDate
FROM #Customers
WHERE DATEDIFF(DD, GETDATE(), DATEADD(YY, DATEDIFF(YY, CustomerBirthDate, GETDATE()), CustomerBirthDate)) BETWEEN -@LastNDays AND 0
DROP TABLE #Customers
``