【问题标题】:SQL - Create row for filling in NULL into missing dates but repeating ID Column ValueSQL - 创建用于将 NULL 填充到缺失日期但重复 ID 列值的行
【发布时间】:2014-06-19 15:30:00
【问题描述】:

我有以下表格。每个员工都有TimeRegister(每一行在asc 序列中等于一个IN 和一个OUT):

Employee         TimeRegister
   15        2014-04-01 11:51:43.000
   15        2014-04-01 14:03:52.000
   15        2014-04-01 14:17:01.000
   15        2014-04-01 16:01:12.000
   15        2014-04-03 09:48:33.000
   15        2014-04-03 12:13:43.000

另一个表有所有日期:

          Date
2014-04-01 00:00:00.000
2014-04-02 00:00:00.000
2014-04-03 00:00:00.000
2014-04-04 00:00:00.000  

您可以在第一张表中注意到,2014 年 4 月 2 日的员工 15 没有记录。但我希望那个日期带有NULL 时间寄存器,所以它看起来像这样:

Employee         TimeRegister
   15        2014-04-01 11:51:43.000
   15        2014-04-01 14:03:52.000
   15        2014-04-01 14:17:01.000
   15        2014-04-01 16:01:12.000
   15                NULL
   15        2014-04-03 09:48:33.000
   15        2014-04-03 12:13:43.000  

我不想将INSERT 放入表格本身,而是使用VIEW 来获取它。

我们将不胜感激所有帮助。提前致谢!

【问题讨论】:

  • 你好。我用Dates 表尝试了一个简单的LEFT JOIN,但它没有用。感谢您的提问。

标签: sql sql-server date row fill


【解决方案1】:

我使用递归 cte 来生成某个范围的所有日期,但如果您说您有另一个包含所有日期(或所有相关/工作日期)的表,请使用它而不是 cteDateGen。同样,我已经从与TimeRegister 相同的表中删除了唯一的员工——同样,您可能还有另一个员工表。获得所有日期和员工的列表后,您可以使用 TimeRegisters 左外连接到表,以确保每个日期/员工组合至少有一行,即使表中没有这样的行:

With cteDateGen AS
(
  SELECT 0 as Offset, CAST(DATEADD(dd, 0, '2014-04-01') AS DATE) AS WorkDate
  UNION ALL 
  SELECT Offset + 1, CAST(DATEADD(dd, Offset, '2014-04-01') AS DATE)
  FROM cteDateGen
  WHERE Offset < 1000
),
cteAllEmployees AS
(
  SELECT DISTINCT(Employee) AS Employee
  FROM TimeRegister
)
SELECT d.WorkDate,
       e.Employee, t.TimeRegister
  FROM cteDateGen d
    CROSS JOIN cteAllEmployees e
    LEFT JOIN TimeRegister t
      ON e.Employee = t.Employee AND CAST(t.TimeRegister AS DATE) = d.WorkDate
  WHERE d.WorkDate BETWEEN '2014-04-01' AND '2014-04-10'
  OPTION(MAXRECURSION 0);    

我假设与小提琴here中的表结构相同

【讨论】:

  • 好东西!完美运行。我刚刚将WHERE d.WorkDate BETWEEN '2014-04-01' AND '2014-04-10' 更改为WHERE d.WorkDate &gt;=(SELECT MIN (d.WorkDate) from TimeRegister) AND 'WHERE d.WorkDate &lt;=(SELECT MAX (d.WorkDate) from TimeRegister),因此它给出了该范围内的所有相关日期。再次感谢!。这非常有效!
【解决方案2】:

这并不完美(它在员工中给出 null 而不是日期,并且仅对年/月/日进行比较是粗略的!))

select Employee, coalesce(TimeRegister, Date)
from Date
left outer join EmpDate 
  on left(cast(Date as nvarchar), 10) = left(cast(TimeRegister as nvarchar), 10)

即给出:

EMPLOYEE    COLUMN_1 
15          April, 01 2014 11:51:43+0000
15          April, 01 2014 14:03:52+0000 
15          April, 01 2014 14:17:01+0000
15          April, 01 2014 16:01:12+0000
(null)      April, 02 2014 00:00:00+0000
15          April, 03 2014 09:48:33+0000 
15          April, 03 2014 12:13:43+0000 
(null)      April, 04 2014 00:00:00+0000

SQL 小提琴链接:http://sqlfiddle.com/#!3/482b1/7/0

【讨论】:

  • 非常感谢您的输入,虽然这不是我想要的,但我会保留此代码 sn-p 以供将来实施。非常感谢!
【解决方案3】:

DB 设计似乎有点不符合您的需要。这将使您获得 NULL 日期,但也会获得 NULL 员工。

SELECT  T.Employee, T.TimeRegister
FROM    DateTable D
LEFT JOIN   TimeRegisterTable T
        ON  convert(date,T.TimeRegister) = convert(date,D.Date)

【讨论】:

    【解决方案4】:

    试试这个查询,假设你的第一个表叫做 a1,第二个叫做 a2:

    select a.Employee,b.TimeRegister from a1 a 
        inner join a2 b on a.TimeRegister=b.TimeRegister
    union
    select x.Employee,null
    from a1 x
    where x.Employee not in (select d.Employee from a1 d 
        inner join a2 e on d.TimeRegister=e.TimeRegister
        where d.Employee=null)
    

    输出:

    15  2014-04-01 11:51:43.000
    15  2014-04-01 14:03:52.000
    15  2014-04-01 14:17:01.000
    15  2014-04-01 16:01:12.000
    15  2014-04-03 09:48:33.000
    15  2014-04-03 12:13:43.000
    15  NULL
    

    【讨论】:

    • 感谢您的意见。真的很感激。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 2020-12-04
    相关资源
    最近更新 更多