如何在SQL表中克隆和修改行?

时间:2016-12-12 13:22:39

标签: sql-server tsql

我使用的是MSSQL 2012。

我有一张名为SensorMeasure的表:

| Id | SensorUnitId| MeasureDate            | AlertType | MeasureValue|   
| 1  |   3379      | 2016-06-05 00:01:34.000|         1 |     4       | 
| 3  |   3381      | 2016-09-18 11:26:33.000|         6 |     5       |
| 4  |   3381      | 2017-03-03 21:46:18.000|         3 |     3       |
| 5  |   3382      | 2016-09-18 11:26:33.000|         5 |     8       |
| 6  |   3381      | 2017-05-03 21:46:18.000|         3 |     0       |

我需要通过SensorUnitId列重复行,然后在通过SensorUnitId进行灌浆后,我需要克隆具有最新日期的行,将AlertType单元格设置为6并将当前日期和时间设置为MeasureDate单元格将它们插入表格中。

这是我期望的结果:

| Id | SensorUnitId| MeasureDate            | AlertType | MeasureValue|   
| 1  |   3379      | 2016-06-05 00:01:34.000|         1 |     4       | 
| 3  |   3381      | 2016-09-18 11:26:33.000|         6 |     5       |
| 4  |   3381      | 2017-03-03 21:46:18.000|         4 |     3       |
| 5  |   3382      | 2016-09-18 11:26:33.000|         5 |     8       |
| 6  |   3381      | 2016-11-03 21:46:18.000|         3 |     0       |
| 7  |   3379      | 2016-12-12 15:30:34.000|         6 |     4       | 
| 8  |   3381      | 2016-12-12 15:30:34.000|         6 |     0       |
| 9  |   3382      | 2016-12-12 15:30:34.000|         6 |     8       |

这是我如何对行进行分组:

SELECT  Max(MeasureDate) as Date, MAX(AlertType) as AlertType,SensorUnitId
FROM SensorsMeasure
GROUP BY SensorUnitId

但我不知道在分组后如何将MeasureDate修改为当前日期和时间以及如何将AlertType设置为6并将这些行插入表中。

更新

正如我已经写过的,我有一个名为SensorMeasure的表。我需要按列SensorUnitId对表中的所有记录进行分组。

记录分组后,我需要从每个gruop记录中获取最新日期。如果获取的记录的值为AlertType,我需要过滤它(忽略它),如果记录的值为AlertType不是6我需要克隆这一行 将AlertType单元格设置为6,并将当前日期和时间设置为MeasureDate单元格,并将其插入表格SensorMeasure

例如我有这张表:

| Id | SensorUnitId|      MeasureDate       | AlertType | MeasureValue|   
| 1  |   3379      | 2016-06-05 00:01:34.000|         1 |     4       | 
| 3  |   3381      | 2016-09-18 11:26:33.000|         6 |     5       |
| 4  |   3381      | 2016-12-03 21:46:18.000|         3 |     3       |
| 5  |   3382      | 2016-09-18 11:26:33.000|         6 |     8       |

所需的表格是:

| Id | SensorUnitId|      MeasureDate       | AlertType | MeasureValue|   
| 1  |   3379      | 2016-06-05 00:01:34.000|         1 |     4       | 
| 3  |   3381      | 2016-09-01 11:26:33.000|         6 |     5       |
| 4  |   3381      | 2016-12-03 21:46:18.000|         3 |     3       |
| 5  |   3382      | 2016-09-18 11:26:33.000|         6 |     8       |
| 6  |   3379      | 2016-12-12 21:20:34.000|         6 |     4       | 
| 7  |   3381      | 2016-12-12 21:20:34.000|         6 |     3       |

2 个答案:

答案 0 :(得分:2)

最新更新

根据我的理解,这是我对问题的重述:

  

如果每个MeasureDate的最新条目(SensorUnitId)没有AlertType = 6,我需要在该表中为该SensorUnitId插入一个新行当前日期,新AlertType和最新MeasurementValue

我认为最简单的方法是使用交叉apply

rextester: http://rextester.com/VBP95454

/* testing setup */
create table SensorsMeasure (Id int,SensorUnitId int,MeasureDate datetime,AlertType int,MeasureValue int)
insert into  SensorsMeasure (Id,SensorUnitId,MeasureDate,AlertType,MeasureValue) values (1,3379,'2016-06-05 00:01:34.000',1,4),(3,3381,'2016-09-18 11:26:33.000',6,5),(4,3381,'2016-12-03 21:46:18.000',3,3),(5,3382,'2016-09-18 11:26:33.000',6,8)
declare @NewAlertType int   ; set @NewAlertType    = 6;
declare @ExceptAlertType int; set @ExceptAlertType = 6;

select * from SensorsMeasure;

--**`cross [apply][4]`** version:

--insert into SensorsMeasure (SensorUnitId, MeasureDate, AlertType, MeasureValue)
select distinct
    SensorUnitId
  , MeasureDate  =   getdate()
  , AlertType    =  @NewAlertType
  , MeasureValue = x.MeasureValue
from SensorsMeasure sm
  cross apply (select top 1 MeasureValue, AlertType
                      from SensorsMeasure i
                      where i.SensorUnitId = sm.SensorUnitId
                      order by MeasureDate desc) as x
where x.AlertType != @ExceptAlertType;

您也可以使用 top with ties 执行此操作(在此实例中无需使用交叉或外部应用)。

rextester: http://rextester.com/JWT74538

--insert into SensorsMeasure (SensorUnitId, MeasureDate, AlertType, MeasureValue)
select top 1 with ties
      sm.SensorUnitId
    , MeasureDate = getdate() 
    , AlertType   = @NewAlertType
    , sm.MeasureValue
  from  SensorsMeasure sm
  where sm.AlertType != @ExceptAlertType
  order by row_number() over (partition by sm.SensorUnitId order by sm.MeasureDate desc);

上一次更新:

看起来我假设它是基于示例数据的最大警报类型。相反,您可以使用AlertType = 6

更新了反映更新的问题:

  

我需要在AlertType = 6之后忽略记录。

我将其解释为忽略SensorUnitIds AlertType

6

测试代码的rextester链接: http://rextester.com/CLA47054

/* testing setup */
create table SensorsMeasure (Id int,SensorUnitId int,MeasureDate datetime,AlertType int,MeasureValue int)
insert into  SensorsMeasure (Id,SensorUnitId,MeasureDate,AlertType,MeasureValue) values (1,3379,'2016-06-05 00:01:34.000',1,4),(3,3381,'2016-09-18 11:26:33.000',6,5),(4,3381,'2017-03-03 21:46:18.000',3,3),(5,3382,'2016-09-18 11:26:33.000',5,8),(6,3381,'2017-05-03 21:46:18.000',3,0);
declare @NewAlertType    int; set @NewAlertType    = 7;
declare @ExceptAlertType int; set @ExceptAlertType = 6;

correlated supquery 版本:

--insert into SensorsMeasure (SensorUnitId, MeasureDate, AlertType, MeasureValue)
  select
      SensorUnitId
    , MeasureDate  = getdate()
    , AlertType    = @NewAlertType
    , MeasureValue = (select top 1 MeasureValue
                        from SensorsMeasure i
                        where i.SensorUnitId = sm.SensorUnitId
                        order by MeasureDate desc)
  from SensorsMeasure sm
  where not exists (
    select 1
      from SensorsMeasure e
      where e.SensorUnitId = sm.SensorUnitId
        and e.AlertType    = @ExceptAlertType
        )
  group by SensorUnitId;
使用 common table expression

row_number()

;with LatestMeasureValue as (
  select
      SensorUnitId
    , MeasureValue
    , rn=row_number() over (partition by SensorUnitId order by MeasureDate desc)
    from SensorsMeasure sm
    where not exists (
    select 1
      from SensorsMeasure e
      where e.SensorUnitId = sm.SensorUnitId
        and e.AlertType    = @ExceptAlertType
        )
)
--insert into SensorsMeasure (SensorUnitId, MeasureDate, AlertType, MeasureValue)
  select
      lmv.SensorUnitId
    , MeasureDate  = getdate()
    , AlertType    = @NewAlertType
    , MeasureValue = lmv.MeasureValue
  from LatestMeasureValue lmv
  where lmv.rn=1

交叉apply 版本:

--insert into SensorsMeasure (SensorUnitId, MeasureDate, AlertType, MeasureValue)
select distinct
    SensorUnitId
  , MeasureDate  =   getdate()
  , AlertType    =  @NewAlertType
  , MeasureValue = x.MeasureValue
from SensorsMeasure sm
  cross apply (select top 1 MeasureValue
                      from SensorsMeasure i
                      where i.SensorUnitId = sm.SensorUnitId
                      order by MeasureDate desc) as x
  where not exists (
    select 1
      from SensorsMeasure e
      where e.SensorUnitId = sm.SensorUnitId
        and e.AlertType    = @ExceptAlertType
        )

<小时/> 老回答:

;with LatestMeasureValue as (
  select
      SensorUnitId
    , MeasureValue
    , rn=row_number() over (partition by SensorUnitId order by MeasureDate desc)
    from SensorsMeasure
)
insert into SensorsMeasure (SensorUnitId, MeasureDate, AlertType, MeasureValue)
  select
      lmv.SensorUnitId
    , MeasureDate = getdate()
    , mat.MaxAlertType
    , lmv.MeasureValue
  from LatestMeasureValue lmv
    cross join (
      select
        MaxAlertType=max(AlertType)
      from SensorsMeasure
      ) as mat
  where lmv.rn=1

这会使用common table expression获取每个MeasureValue的最新SensorUnitId,然后交叉加入查询以使max(AlertType)添加最多AlertType对于每个最新值,最后使用getdate()作为新的MeasureDate

你也可以通过其他方式做到这一点。

此方法仅使用子查询和correlated subquery

insert into SensorsMeasure (SensorUnitId, MeasureDate, AlertType, MeasureValue)
  select
      SensorUnitId
    , MeasureDate  = getdate()
    , AlertType    = (select max(AlertType) from SensorsMeasure)
    , MeasureValue = (select top 1 MeasureValue
                        from SensorsMeasure i
                        where i.SensorUnitId = sm.SensorUnitId
                        order by MeasureDate desc)
  from SensorsMeasure sm
  group by SensorUnitId;

答案 1 :(得分:1)

使用TOP WITH TIES + ROW_NUMBER的另一种方式:

DECLARE  @alerttype int = 6

--INSERT INTO SensorMeasure
SELECT top 1 with ties
        s.SensorUnitId,
        GETDATE() as MeasureDate,
        @alerttype as AlertType,
        s.MeasureValue
FROM SensorMeasure S
left join (select distinct SensorUnitId from SensorMeasure where AlertType =6) s1 
on s1.SensorUnitId = s.SensorUnitId 
WHERE s1.SensorUnitId is null
ORDER BY ROW_NUMBER() OVER (PARTITION BY s.SensorUnitId ORDER BY s.MeasureDate DESC)

输出:

SensorUnitId MeasureDate             AlertType   MeasureValue
------------ ----------------------- ----------- ------------
3379         2016-12-12 17:06:35.953 6           4
3382         2016-12-12 17:06:35.953 6           8

(2 row(s) affected)

修改

如果您只需要最新而不是AlertType = 6,则可以添加一些OUTER APPLY

DECLARE  @alerttype int = 6

--INSERT INTO SensorMeasure
SELECT top 1 with ties
        s.SensorUnitId,
        GETDATE() as MeasureDate,
        @alerttype as AlertType,
        s.MeasureValue
FROM SensorMeasure S
OUTER APPLY (
    SELECT TOP 1 * 
    FROM SensorMeasure 
    WHERE SensorUnitId = s.SensorUnitId 
    ORDER BY MeasureDate DESC
        ) s1 
WHERE s1.AlertType != @alerttype
ORDER BY ROW_NUMBER() OVER (PARTITION BY s.SensorUnitId ORDER BY s.MeasureDate DESC)

输出:

SensorUnitId MeasureDate             AlertType   MeasureValue
------------ ----------------------- ----------- ------------
3379         2016-12-13 10:05:39.377 6           4
3381         2016-12-13 10:05:39.377 6           3

(2 row(s) affected)