如何构建用于老化的CaseStatement

时间:2014-07-30 22:44:41

标签: sql sql-server date case

我是这里的新手,非常感谢任何帮助。我需要创建一个老化设置为> 3个月,> 6个月,> 9个月的报告。

报告应该只有3列(3个月,> 6个月,> 9个月)。在表/数据库中假设我们只有两个字段。一个是WELL_ID,用于标识井的名称和RECORD_DATE(mm / dd / yyyy),用于标识上次测试WELL的时间。我们希望报告能够在3个月或> 6个月或> 9个月内进行测试。

我相信一个案例陈述可以放在一起来创建这个结果集,但我在如何做到这一点上画了一个空白。如果有人可以使用Case Statement发布解决方案,那将非常感激。如果他们甚至可以花时间向我解释解决方案,那么帮助我理解会更好。

此致

SQL新手

3 个答案:

答案 0 :(得分:1)

如果你想获得3列> 3个月,> 6个月,> 9个月,每个人使用well_id返回,我可以告诉你如何在SQL中执行此操作。但是,最好在报表级别执行此操作,并且仅分别从SQL检索每个列。这是微不足道的,其他人已经给你一些例子。

让我们开始吧。首先,SQL中的datediff不是人们期望它的行为方式。您可以在this article中阅读有关它的所有内容。让我们从那里借用一个函数:

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fnMonthsApart]') AND type in (N'FN'))
DROP FUNCTION dbo.fnMonthsApart
GO

CREATE FUNCTION dbo.fnMonthsApart
(
        @FromDate DATETIME,
        @ToDate DATETIME
)
RETURNS INT
AS
BEGIN
        RETURN  CASE
                       WHEN @FromDate > @ToDate THEN NULL
                       WHEN DATEPART(day, @FromDate) > DATEPART(day, @ToDate) THEN DATEDIFF(month, @FromDate, @ToDate) - 1
                       ELSE DATEDIFF(month, @FromDate, @ToDate)
               END
END
GO

出色!现在让我们定义我们的表格:

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Well]') AND type in (N'U'))
DROP TABLE [dbo].[Well]
GO

CREATE TABLE [dbo].[Well](
  [WELL_ID] [int] IDENTITY(1,1) NOT NULL,
  [RECORD_DATE] [datetime] NOT NULL,
 CONSTRAINT [PK_Well] PRIMARY KEY CLUSTERED 
(
  [WELL_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

以及一些示例数据:

declare @date datetime = dateadd(d,-1,getdate())


INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-12,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-9,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-9,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-9,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-9,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-9,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-6,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-6,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-6,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-6,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-3,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-3,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (dateadd(m,-3,@date))
INSERT INTO [dbo].[Well]([RECORD_DATE]) VALUES (@date)
GO

到目前为止,非常好。

现在,技巧是分别检索三列,然后将它们连接在一个记录集中。以下是如何做到这一点:

declare @date datetime = getdate();
with AgeGrouping as
(select 
  WELL_ID,
  dbo.fnMonthsApart(record_date,@date) MonthsAgo,
  case 
    when dbo.fnMonthsApart(record_date,@date) >= 9 then 1 
    when dbo.fnMonthsApart(record_date,@date) >= 6 then 2 
    when dbo.fnMonthsApart(record_date,@date) >= 3 then 3 
    else 4
  end AgeGroup,
  ROW_NUMBER() OVER (partition by  
    case 
      when dbo.fnMonthsApart(record_date,@date) >= 9 then 1 
      when dbo.fnMonthsApart(record_date,@date) >= 6 then 2 
      when dbo.fnMonthsApart(record_date,@date) >= 3 then 3 
      else 4
    end 
  order by WELL_ID) RowNumber
from well
),
MoreThan9Group as
(select * from AgeGrouping where AgeGroup = 1
),
MoreThan6Group as
(select * from AgeGrouping where AgeGroup = 2
),
MoreThan3Group as
(select * from AgeGrouping where AgeGroup = 3
)
select g1.WELL_ID MoreThan9,g2.WELL_ID MoreThan6,g3.WELL_ID MoreThan3
from MoreThan9Group g1 full join MoreThan6Group g2 on (g1.RowNumber = g2.RowNumber)
full join MoreThan3Group g3 on ((g1.RowNumber = g3.RowNumber) or (g2.RowNumber = g3.RowNumber)) 

请注意,我在此SQL中有>=而不是>。这是因为1月1日到4月2日之间的差异超过3个月,但3是我们比较它们时返回的数字。因此,3的结果符合您的要求,因此我们将>更改为>=以包含它。

就是这样。

这是SqlFiddle demo

答案 1 :(得分:0)

我不确定这是否是您正在寻找的。我还没试过。

CASE语句检查DATEDIFF函数返回的值。取决于该值是> 9或> 6或> 3或< = 3,确定test_Status。

SELECT well_ID,
       record_Date,
CASE 
    WHEN DATEDIFF(month, record_Date, GETDATE()) >= 9
    THEN 'Not Tested In More Than 9 Months'
    WHEN DATEDIFF(month, record_Date, GETDATE()) >= 6
    THEN 'Not Tested In More Than 6 Months'
    WHEN DATEDIFF(month, record_Date, GETDATE()) >= 3
    THEN 'Not Tested In More Than 3 Months'
    ELSE 'Tested Within Last 3 Months'
END AS test_Status
FROM WellTable;

答案 2 :(得分:0)

您可以根据以下逻辑首先计算RECORD_DATE和今天之间的月数:

a)如果RECORD_DATE的日期部分>今天的部分日期+ 1,然后是#个月=使用DATEDIFF获得的月数#1

b)如果RECORD_DATE的日期部分不是>今天的部分日期+ 1,然后是#个月=使用DATEDIFF获得的月份数

然后,根据月数,确定状态。

WITH month_interval AS
(
    SELECT
        WELL_ID,
        CASE
            WHEN DATEPART(DAY, RECORD_DATE) > DATEPART(DAY, GETDATE())+1 THEN DATEDIFF(MONTH, RECORD_DATE, GETDATE())-1
            ELSE DATEDIFF(MONTH, RECORD_DATE, GETDATE())
        END num_months
    FROM WellTable
)
SELECT 
    wt.WELL_ID,
    wt.RECORD_DATE,
    CASE 
        WHEN mi.num_months >= 9 THEN 'Not Tested In More Than 9 Months'
        WHEN mi.num_months >= 6 THEN 'Not Tested In More Than 6 Months'
        WHEN mi.num_months >= 3 THEN 'Not Tested In More Than 3 Months'
        ELSE 'Tested Within Last 3 Months'
    END AS TEST_STATUS
FROM WellTable wt
INNER JOIN month_interval mi
ON wt.WELL_ID = mi.WELL_ID;