在where子句中不使用函数来计算年龄

问题描述 投票:0回答:1

我一直在阅读有关避免在 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。

如有任何建议,我们将不胜感激。

亲切的问候, 斯蒂芬

sql-server function date t-sql where-clause
1个回答
0
投票

我认为上面给出的答案大多是有效的,但是,我个人非常不喜欢计算列,无论它们是直接在表定义中定义的,还是通过作业来维护的。我不喜欢前者,因为它们会造成尴尬的索引 - 为了索引计算列,您需要将其持久化,这意味着每当您更新表中的值时都需要重新计算该列,并且我不喜欢后者,因为它们依赖工作。

如果您的目标只是让您的年龄计算与您所询问的

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
``
© www.soinside.com 2019 - 2024. All rights reserved.