【问题标题】:Insert Month and Day only仅插入月份和日期
【发布时间】:2013-08-15 04:19:19
【问题描述】:

我目前正在制作一个计算机化的工资单系统,但我不知道应该使用什么查询来检查员工在假期期间是否在场。

我所做的是我创建了这个查询:

CREATE TABLE Holidays
(
      id INT PRIMARY KEY IDENTITY,
      holidayName VARCHAR(55),
      holidayDate DATE <---- This is my problem
);

CREATE TABLE EmployeeHolidays
(
     id INT PRIMARY KEY IDENTITY,
     employeeId INT FOREIGN KEY REFERENCES Employees(id),
     holidayId INT FOREIGN KEY REFERENCES Holidays(id),
     workingDate DATE,
     employeeTimeIn TIME,
     employeeTimeOut TIME
);

现在问题在于在 Holidays.holidayDate 中插入 DATE,因为我必须插入年份,即使我只需要月份来使用 C# 为 EmployeeHolidays 执行条件语句。

我应该使用什么方法来解决这个问题?我应该只输入一个虚拟年份作为Holidays.holidayDate 的输入吗?我是否应该将 Holidays.holidayDate 设为 VARCHAR 并将其与当前年份一起解析为 DATE 数据类型?对于这种方法,我应该使用哪些查询?

【问题讨论】:

  • 我很好奇为什么holidayDate 不应该有年份部分。
  • 您可以创建一个函数IsHoliday 并一起删除假期表,我发现最难的部分是计算复活节。或者这可能都是更大的日历表的一部分,该表具有 IsHolidayIsWeekEnd 等,这对于此类应用程序似乎很有用
  • 很多假期——总统日、斋月、感恩节——每年都会改变日期。拥有静态的“示范假期”可能不是最好的方法。在类似的情况下,我创建了一个存储过程,它将生成给定年份的假期(如果它们不存在于表中),然后我将匹配日期与日期。结果很好。使用起来效率更高,因为您可以使用直接 SQL 连接逻辑来检查一天是否是假期。
  • FWIW,我遇到了完全相同的问题,最终创建了一个日历表,其中包含一个带有原因字段的 WorkingDay 标志。我个人允许工资单管理假期,但实际上并没有太多(我的公司在美国,只在最常见的假期放假)需要自动化。事实证明,它难以置信地方便并且几乎简化了我的所有报告。在使用这些类型的系统时,您通常会发现自己围绕日历构建报告。

标签: c# sql sql-server tsql sql-insert


【解决方案1】:

使用虚拟年份,您会遇到诸如不允许使用 2 月 29 日等问题,具体取决于所使用的虚拟年份,尽管如果是闰年,今年可能存在 2 月 29 日。

我建议您将实际的完整假期日期与年份一起存储,如果您在计算中不使用年份,那是您的事,但为什么要存储其他值呢?

【讨论】:

    【解决方案2】:

    由于在大多数国家/地区,日期假期每年都在变化,由于周末,您应该使用完整日期格式的日期。

    此外,我认为您应该存储已非规范化的Calendar 表。

    使用列如:

    • 日期
    • 自给定开始日期以来的天数(例如 1-1-1900)

    • 给定开始日期的工作日(例如 1-1-1900)

    • 一年中的一周
    • 月月
    • 白天部分
    • DayOfWeek
    • 第 # 季
    • 每月的第一天
    • 季度第一天
    • 是周末
    • 是假期(+描述)

    一旦您填写了这样的表格,您就可以轻松地进行具有最佳性能的日期数学运算。提供这样一张桌子的样本是here

    请注意,如果您需要支持多个国家/地区,您可能需要添加 CountryCode 列来保存每个国家/地区的日历。

    【讨论】:

      【解决方案3】:

      您可以将假日的日期和月份存储为 int 类型的单独字段。然后在查询时可以使用月和日函数。

      【讨论】:

        【解决方案4】:

        创建日期使用函数:

        CREATE FUNCTION dbo.MyDate(@M INT, @D INT)
          RETURNS DATE
        AS
        BEGIN  
          RETURN DATEADD(MONTH, @M - 1, (DATEADD(DAY, @D - 1, 0)))
        END  
        
        SELECT dbo.MyDate(2, 10)
        

        或当前年份:

        CREATE FUNCTION dbo.MyDate(@M INT, @D INT)
          RETURNS DATE
        AS
        BEGIN  
          RETURN DATEADD(YEAR, YEAR(GETDATE()) - 1900, DATEADD(MONTH, @M - 1, (DATEADD(DAY, @D - 1, 0))))
        END 
        

        【讨论】:

          【解决方案5】:

          我会使用带有CHECK 约束的DATE 列,因此:

          CREATE TABLE Holidays
          (
              ...
              HolidayDate DATE NOT NULL,
              CONSTRAINT CK_Holidays_VerifyYearOfHolidayDate CHECK( YEAR(HolidayDate)=1 )
          );
          

          原因:

          • 您将获得MONTHDAY 验证。否则,如果我将使用带有四位数字的SMALLINT 列(例如,MMDD,MM= 两位数表示月份,DD=两位数表示日)。此外,我将不得不添加另一个约束来验证 MM (1
          • 我可以使用日期函数DAYMONTHDATEPART 等。如果我要使用SMALLINT 列,那么我将使用 / 和 % 运算符来获取月份和日期(例如 1231 / 100 = 12 和 1231 % 100 = 31)。

          我会定义一个函数,它需要一年和 HolidayDate 作为参数并返回全年:

          CREATE FUNCTION dbo.HolidayDateWithYear(@YYYY SMALLINT, @HolidayDate DATE)
          RETURNS DATE
          WITH SCHEMABINDING    
          AS
          BEGIN
          RETURN DATEADD(YEAR,@YYYY,@HolidayDate);
          END;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-01-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-11-06
            • 1970-01-01
            相关资源
            最近更新 更多