【问题标题】:SQL Server NULL replacement with dynamic valueSQL Server NULL 用动态值替换
【发布时间】:2018-02-01 12:41:48
【问题描述】:

我希望将 NULL 值替换为基于表中数据的模式值。

在下面的示例中,我想将 EquipmentID 的 NULL InDate 替换为该 ProcessID 的 InDates 的模式值。我已经计算了 ProcessID 的模式 InDate,我只是不知道如何使用该值来用 ProcessID 替换 EquipmentID 的 NULL 值

这是一个示例设置:

 CREATE TABLE dbo.Table_basic (
                InDate INT,
                EquipmentID INT,
                ProcessID nvarchar(50),
                SiteID INT
                )

INSERT INTO Table_basic (InDate, EquipmentID, ProcessID, SiteID)
VALUES (2001, 1,'1PAA',1),
        (2001,2,'1PAA',1),
        (NULL, 3,'1PAA',1),
        (2001,4,'1PAA',1),
        (1999, 5,'1PAA',1),
        (2001,6,'1PAB',1),
        (2001,7,'1PAC',1),
        (2001, 8,'2AA',2),
        (1999,9,'2AB',2),
        (NULL, 10,'2AB',2),
        (1999,11,'2AB',2),
        (1998,12,'2AB',2),
        (2001, 13,'2AB',2),
        (1999,14,'2AB',2),
        (2001, 15,'2AC',2),
        (2001,16,'2AC',2),
        (1986, 17,'3AA',3),
        (1985,18,'3AA',3),
        (1985,19,'3AA',3),
        (NULL, 20,'3AC',3),
        (2005,21,'3AC',3),
        (2005, 22,'3AC',3),
        (2005,23,'3AC',3);

这就是我如何在 ProcessID 中找到设备的 InDate 模式。

WITH CTE_CountofEquipment AS
 (
  SELECT
    ProcessID
   ,SiteID
   ,cnt   = COUNT(1)
   ,rid   = ROW_NUMBER() OVER (PARTITION BY ProcessID ORDER BY COUNT(1) DESC)
   ,InDate
    FROM dbo.Table_basic 
  GROUP BY  SiteID, ProcessID, InDate
 )
 SELECT
   ProcessID
  ,cnt = cnt
  ,[SiteID]
  ,InDate
 FROM CTE_CountofEquipment
 WHERE rid = 1
 ORDER BY SiteID;

我想使用这些确定的模式来填充给定 ProcessID 的 NULL InDate。

期望的结果示例:

(NULL, 3,'1PAA',1),
(2001, 3,'1PAA',1),
(2001, 3,'1PAA',1),
(1999, 3,'1PAA',1),
(2000, 3,'1PAA',1),
(2001, 3,'1PAA',1),

变成

(2001, 3,'1PAA',1), -- InDate updated to modal value
(2001, 3,'1PAA',1),
(2001, 3,'1PAA',1),
(1999, 3,'1PAA',1),
(2000, 3,'1PAA',1),
(2001, 3,'1PAA',1),

谢谢

【问题讨论】:

  • 您是否正在更新 ProcessID='1PAA' 的 InDate 最大值??
  • 我不明白给定示例的结果,请您详细说明
  • 嗨 Rams,不,我希望通过 InDate 模式更新 ProcessID='1PAA'
  • TheGameiswar,请参阅编辑。我已更新以使期望的结果更清晰。

标签: sql sql-server ssms-17


【解决方案1】:

我会这样计算:

with modes as (
      select p.*
      from (select tb.processId, tb.indate, count(*) as cnt,
                   row_number() over (partition by tb.processId order by count(*) desc) as seqnum
            from table_basic tb
            group by tb.processId, tb.indate
           ) p
      where seqnum = 1
     )
update tb
    set indate = m.indate
    from table_basic tb join
         modes m
         on tb.processId = m.processId
    where indate is null;

这回答了您的问题。我不知道为什么你的模式计算使用SiteId。这不是问题的一部分。我不知道对EquipmentIdNULL 值的引用是什么。这也不是问题的一部分。

但是,您应该能够轻松地为模式或其他列的其他分组进行修改。

【讨论】:

  • 太棒了,这成功了。
【解决方案2】:

您可以使用如下查询来执行UPDATE

;WITH CTE_CountofEquipment AS (
    SELECT InDate, ProcessID, SiteID, 
           COUNT(*) OVER (PARTITION BY ProcessID, SiteID, InDate) AS cnt
    FROM dbo.Table_basic
), ToUpdate AS (
   SELECT InDate, ProcessID, SiteID,
          FIRST_VALUE(InDate) 
          OVER 
             (PARTITION BY ProcessID, SiteID
             ORDER BY cnt DESC ) AS mode
    FROM CTE_CountofEquipment
)
UPDATE ToUpdate
SET InDate = mode
WHERE InDate IS NULL

查询使用窗口函数计算mode值:

  • COUNT OVER() 用于确定每个 ProcessID, SiteID 分区内每个 InDate 切片的数量
  • FIRST_VALUE(InDate) is used to select theInDate` 拥有最多的人口

Demo here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 2022-11-22
    • 1970-01-01
    • 1970-01-01
    • 2022-08-16
    • 2013-08-03
    相关资源
    最近更新 更多