【问题标题】:merging records for sql table based on column data基于列数据合并sql表的记录
【发布时间】:2012-03-27 08:38:45
【问题描述】:

我在 t_resourcetable 中有一些脏资源使用记录,看起来像这样

resNo subres startdate enddate 1 2 2012-01-02 22:03:00.000 2012-01-03 00:00:00.000 1 2 2012-01-03 00:00:00.000 2012-01-04 00:00:00.000 1 2 2012-01-04 00:00:00.000 2012-01-04 16:23:00.000 1 3 2012-01-06 16:23:00.000 2012-01-06 22:23:00.000 2 2 2012-01-04 05:23:00.000 2012-01-06 16:23:00.000

我需要以这种方式合并那些脏行

resNo subres startdate enddate 1 2 2012-01-02 22:03:00.000 2012-01-04 16:23:00.000 1 3 2012-01-06 16:23:00.000 2012-01-06 22:23:00.000 2 2 2012-01-04 05:23:00.000 2012-01-06 16:23:00.000

这应该更新到同一个表,我有超过 40k 行所以不能使用游标请帮助我通过一些优化的 sql 语句清理这种数据。

提供了 temptable 和 group 的解决方案不会遇到类似的场景。 我正在寻找没有基于光标的解决方案来解决这个问题

resNo subres startdate enddate 1 2 2012-01-02 22:03:00.000 2012-01-03 00:00:00.000 1 2 2012-01-03 00:00:00.000 2012-01-04 00:00:00.000 1 2 2012-01-04 00:00:00.000 2012-01-04 16:23:00.000 1 2 2012-01-14 10:09:00.000 2012-01-15 00:00:00.000 1 2 2012-01-15 00:00:00.000 2012-01-16 00:00:00.000 1 2 2012-01-16 00:00:00.000 2012-01-16 03:00:00.000 1 3 2012-01-06 16:23:00.000 2012-01-06 22:23:00.000 2 2 2012-01-04 05:23:00.000 2012-01-06 16:23:00.000

我需要以这种方式合并那些脏行

resNo subres startdate enddate 1 2 2012-01-02 22:03:00.000 2012-01-04 16:23:00.000 1 2 2012-01-14 10:09:00.000 2012-01-16 03:00:00.000 1 3 2012-01-06 16:23:00.000 2012-01-06 22:23:00.000 2 2 2012-01-04 05:23:00.000 2012-01-06 16:23:00.000

请带我摆脱这个脏数据问题

【问题讨论】:

标签: c# sql-server database tsql stored-procedures


【解决方案1】:

您需要像这样按 resNo 和 subRes 对数据进行分组:

select resNo, subRes, min(startdate), max(enddate)
from  t_resourcetable
group by resNo, subRes

并将结果插入到临时表中。

然后你可以截断 t_resourcetable 并将临时 tample 中的结果插入其中

【讨论】:

  • 它不会起作用,因为资源 1 的数据被使用了两次,并且 group by 将只返回一行,而实际结果应该是 resourceno(1) 和 subres(2) 的 2 行跨度>
  • 按这两个字段分组:resNo, subRes
  • 是的,它是通过对这两个字段 resno,subres 进行分组,通过分组它为同一资源在不同日期的两次不同用途创建一条记录。理想情况下应该是两行
【解决方案2】:

第一步是创建备份:

select * 
into t_resourcetable_backup20120327
from t_resourcetable

然后更新按 resNo 和 subRes 分组的第一条记录的结束日期:

update t_resourcetable
set enddate = (select max (enddate) 
                 from t_resourcetable t1 
                where t1.resNo = t_resourcetable.resNo
                  and t1.subRes = t_resourcetable.subRes)
 where not exists (select null
                 from t_resourcetable t1
                where t1.resNo = t_resourcetable.resNo
                  and t1.subRes = t_resourcetable.subRes
                  and t1.startdate < t_resourcetable.startdate)

最后删除多余的记录:

delete t_resourcetable
 where exists (select null
                 from t_resourcetable t1
                where t1.resNo = t_resourcetable.resNo
                  and t1.subRes = t_resourcetable.subRes
                  and t1.startdate < t_resourcetable.startdate)

如果 resNo 和 subRes 的唯一组合的开始日期重复,这将留下重复。您还应该检查 enddates 是否总是有相应的 startdates,因为您会丢失空白 - 但这可能正是您想要的。

除了创建备份之外,您还可以在事务中包装更新/删除,在删除和回滚后进行选择,然后检查 Excel 中的数据,如果一切正常,请重复事务但这次提交。

更新:此查询识别差距。如果您使用的是 Sql Server 2000,请将 CTE 转换为派生表。首先返回没有前任的资源列表,最后对后继者执行相同的操作。两者都计算差距。然后通过 resNo、subRes 和 gap number 加入列表。

;with first as (
    select resNo, subres, startdate,
  row_number() over (partition by resNo, subres order by startdate) rowNumber
      from t_resourcetable
     where not exists (select null
                       from t_resourcetable t1
                      where t1.resNo = t_resourcetable.resNo
                        and t1.subres = t_resourcetable.subres
                        and t1.enddate = t_resourcetable.startdate)
),
last as (
  select resNo, subres, enddate,
  row_number () over (partition by resNo, subres order by enddate) rowNumber
  from t_resourcetable
     where not exists (select null
                       from t_resourcetable t1
                      where t1.resNo = t_resourcetable.resNo
                        and t1.subres = t_resourcetable.subres
                        and t1.startdate = t_resourcetable.enddate)
)
select first.resno, first.subres, first.startdate, last.enddate
from first 
  inner join last
  on first.resNo = last.resNo
    and first.subres = last.subres
    and first.rowNumber = last.rowNumber

【讨论】:

  • 这不会返回资源 1 和子资源 2 的两行,从 1-(2/1/2012-4/1/2012) 2-(14/1/2012-16/ 1/2012)。相反,这将导致只有一行(2/1/2012-16/1/2012)作为持续的资源使用感谢您的回复 nikola
  • @steavefinner 你试过了吗?如果您有 resno 和 subres 的索引,我认为不会花费很多时间。
【解决方案3】:

你可以试试这个?

SELECT resno,
       subres,
       startdate,
       MIN(enddate) AS enddate
FROM   (SELECT t1.resno,
               t1.subres,
               t1.startdate,
               t2.enddate
        FROM   t_resourcetable t1,
               t_resourcetable t2
        WHERE  t1.enddate <= t2.enddate
               AND NOT EXISTS (SELECT *
                               FROM   t_resourcetable t3
                               WHERE  ( t1.resno = t3.resno
                                        AND t1.subres = t3.subres
                                        AND t1.startdate > t3.startdate
                                        AND t1.startdate <= t3.enddate )
                                       OR ( t2.resno = t3.resno
                                            AND t2.subres = t3.subres
                                            AND t2.enddate >= t3.startdate
                                            AND t2.enddate < t3.enddate )))t
GROUP  BY resno,
          subres,
          startdate 

图片是这样的

【讨论】:

    猜你喜欢
    • 2020-04-14
    • 1970-01-01
    • 2020-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多