从表中获取缺少的月份

时间:2015-11-15 07:58:56

标签: sql sql-server-2008 sql-server-2012

我有一个存储EmployeeId, TourMonth, StartMonth, EndMonth的表。

TourMonth代表月份,1代表1月,2代表2月等。

我想从此表中找到给定startdateenddate之间的缺失月份。以下为1月至12月的员工3071的示例,缺少2月,4月,7月,9月。如何从表格中获得结果?

EmployeeId   TourMonth   StartMonth                    EndMonth
---------    ---------   ---------                     --------
3071               1     2015-01-13 00:00:00.000       2015-01-14 00:00:00.000
3071               3     2015-03-15 00:00:00.000       2015-04-15 00:00:00.000
3071               5     2015-05-15 00:00:00.000       2015-06-15 00:00:00.000
3071               6     2015-06-15 00:00:00.000       2015-07-15 00:00:00.000
3071               8     2015-08-15 00:00:00.000       2015-09-15 00:00:00.000
3071               10    2015-10-15 00:00:00.000       2015-11-15 00:00:00.000

我想要的输出:

如果我传入startdate = 2015-01-01enddate = 2015-11-01以及EmployeeId = 3071,那么我应该得到:

EmployeeId    MissingMonth
-----------   ------------
 3071          February 
 3071          April
 3071          July
 3071          September 

2 个答案:

答案 0 :(得分:1)

使make代码更直接,创建具有月份名称的表:

IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID('[dbo].[tbl_Months]') AND type IN ('U'))
    DROP TABLE [dbo].[tbl_Months]
GO
CREATE TABLE [dbo].[tbl_Months] (
    [id] int NULL,
    [month] varchar(20) COLLATE Latin1_General_CI_AS NULL
)
ON [PRIMARY]
GO

-- ----------------------------
--  Records of tbl_Months
-- ----------------------------
BEGIN TRANSACTION
GO
INSERT INTO [dbo].[tbl_Months] VALUES ('1', 'January');
INSERT INTO [dbo].[tbl_Months] VALUES ('2', 'February');
INSERT INTO [dbo].[tbl_Months] VALUES ('3', 'March');
INSERT INTO [dbo].[tbl_Months] VALUES ('4', 'April');
INSERT INTO [dbo].[tbl_Months] VALUES ('5', 'May');
INSERT INTO [dbo].[tbl_Months] VALUES ('6', 'June');
INSERT INTO [dbo].[tbl_Months] VALUES ('7', 'July');
INSERT INTO [dbo].[tbl_Months] VALUES ('8', 'August');
INSERT INTO [dbo].[tbl_Months] VALUES ('9', 'September');
INSERT INTO [dbo].[tbl_Months] VALUES ('10', 'October');
INSERT INTO [dbo].[tbl_Months] VALUES ('11', 'November');
INSERT INTO [dbo].[tbl_Months] VALUES ('12', 'December');
GO
COMMIT

然后简单选择:

SELECT [id], [month] from tbl_Months 
WHERE NOT EXISTS (SELECT TourMonth FROM table_name WHERE "some conditions")

我没有解释某些条件,因为它可能有很多变种

  • 您可以完全按照日期进行比较 - 例如StartMonth ='2015-10-15'with start_date ='2015-10-16'可以包括本月,不能包括依赖逻辑。
  • 或部分日期(MONTH),具体取决于您的逻辑

答案 1 :(得分:0)

您可以内联注入1-12个月的行,但您可能会发现物理date table非常有用。

下面是一个简单的内联示例:

declare @EmployeeTours table (EmployeeId int, TourMonth int, StartMonth datetime, EndMonth datetime);
insert into @EmployeeTours
values
(3071, 1,    '2015-01-13 00:00:00.000',     '2015-01-14 00:00:00.000'),
(3071, 3,    '2015-03-15 00:00:00.000',     '2015-04-15 00:00:00.000'),
(3071, 5,    '2015-05-15 00:00:00.000',     '2015-06-15 00:00:00.000'),
(3071, 6,    '2015-06-15 00:00:00.000',     '2015-07-15 00:00:00.000'),
(3071, 8,    '2015-08-15 00:00:00.000',     '2015-09-15 00:00:00.000'),
(3071, 10,   '2015-10-15 00:00:00.000',     '2015-11-15 00:00:00.000')

declare @EmployeeId int = 3071,
        @StartMonth datetime = '2015-01-01',
        @EndMonth datetime = '2015-11-01';

select  @EmployeeId, datename(month, dateadd(month, d.TourMonth, 0)-1)
from    (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12))d(TourMonth) 
left
join    @EmployeeTours et on 
        d.TourMonth = et.TourMonth and
        StartMonth >= @StartMonth and
        EndMonth <= @EndMonth and
        EmployeeId = @EmployeeId
where   et.EmployeeId is null
group
by      EmployeeId, d.TourMonth

返回:

3071    February
3071    April
3071    July
3071    September
3071    October
3071    November
3071    December