【问题标题】:Get Missing Month from table从表中获取缺少的月份
【发布时间】:2015-11-16 05:25:35
【问题描述】:

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

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

我想从这张表中找到给定的startdateenddate 之间的缺失月份。下面给出了员工 3071 从 1 月到 12 月的示例,缺少 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-01EmployeeId = 3071,那么我应该得到:

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

【问题讨论】:

  • 期望的输出是什么?
  • @GiorgiNakeuri 我添加了编辑问题

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


【解决方案1】:

为了使代码更直接,创建带有月份名称的表:

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")

我不解释 WHERE 某些条件,因为它可能有很多变体

  • 您可以按日期精确比较 - 例如 StartMonth = '2015-10-15' 和 start_date = '2015-10-16' 可以包括本月,不能包括根据逻辑。
  • 或部分日期(MONTH)取决于您的逻辑

【讨论】:

  • 我不想创建tbl_Months
  • 这是最紧凑的方式(不想创建永久表 - 创建临时表)但当然可以在不创建表的情况下实现 - 检查这个stackoverflow.com/questions/9113204/… 几乎相同的任务 - 如何从列表中选择元素,表中未列出的
【解决方案2】:

您可以内联注入 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

【讨论】:

  • 这是我想要的很好的答案,但我有一个包含 EmplyeeId 和 EmployeeName 的表 Employee 我想用 Inner Join 显示employeeName 我如何在需要更改的这个脚本中执行此操作跨度>
  • @A.Goutam,您将使用日期表中的 left 连接到员工,然后在员工端过滤空值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-01
  • 1970-01-01
相关资源
最近更新 更多