SQL Server 2008 - 检索最近的非空数据

SQL Server 2008 - Retrieve the nearest non null data

我有两个 tables:table 1 a package_id 和一个时间戳列,我没有可用的重量信息,table 2 a package_id、时间戳和权重列,我确实有信息。

我要做的是根据 table 2 使用以下限制填写 table 1 权重信息:

  1. 使用最接近的 package_id 可用,即。对于 package_id 1 如果可用则使用 2,如果不可用则使用 3 etc
  2. 如果只有一个重量可用,请使用它来弥补所有缺失的 package_id 的
  3. 如果有两个权重可用,请使用较高的一个,即。对于 package_id 5,如果 4 和 6 可用,则使用 6

代码:

IF OBJECT_ID('tempdb..#TIMEGAPS') IS NOT NULL DROP TABLE #TIMEGAPS
CREATE TABLE #TIMEGAPS (PACK_ID INT, Local_Time DATETIME)

IF OBJECT_ID('tempdb..#REALVALUES') IS NOT NULL DROP TABLE #REALVALUES
CREATE TABLE #REALVALUES (PACK_ID INT, Local_Time DATETIME, WEIGHT INT)


INSERT INTO #TIMEGAPS VALUES
(1,'2018-01-20 18:40:00.000'),
(1,'2018-01-20 18:50:00.000'),
(1,'2018-01-20 19:00:00.000'),
-----------------------------
(7,'2018-01-20 18:40:00.000'),
(7,'2018-01-20 18:50:00.000'),
(7,'2018-01-20 19:00:00.000'),
------------------------------
(12,'2018-01-20 18:40:00.000'),
(12,'2018-01-20 18:50:00.000'),
(12,'2018-01-20 19:00:00.000'),
(12,'2018-01-20 20:00:00.000')


INSERT INTO #REALVALUES VALUES
(2,'2018-01-20 18:40:00.000',50),
(3,'2018-01-20 18:40:00.000',70),
(4,'2018-01-20 18:40:00.000',150),
(5,'2018-01-20 18:40:00.000',60),
(6,'2018-01-20 18:40:00.000',45),
(8,'2018-01-20 18:40:00.000',55),
(9,'2018-01-20 18:40:00.000',25),
---------------------------------
(2,'2018-01-20 18:50:00.000',75),
(3,'2018-01-20 18:50:00.000',80),
(4,'2018-01-20 18:50:00.000',120),
(5,'2018-01-20 18:50:00.000',110),
(11,'2018-01-20 18:50:00.000',30),
---------------------------------
(8,'2018-01-20 19:00:00.000',70)

编辑: 我已经改编了 的解决方案,我相信这是我需要的。

SELECT tg.PACK_ID, tg.Local_Time, p.WEIGHT
  FROM #TIMEGAPS tg
OUTER APPLY 
(
  SELECT TOP 1 *, ABS(tg.PACK_ID - rv.PACK_ID) AS diff
     FROM #REALVALUES rv
     WHERE (tg.Local_Time = rv.Local_time OR rv.Local_time is null)
     ORDER BY CASE WHEN rv.Local_time IS NULL THEN 2 ELSE 1 END,
     ABS(rv.PACK_ID- tg.PACK_ID) ASC
 ) p

编辑 2: 3. 如果有两个权重可用,则使用最高的 PACK_ID 即。对于 package_id 5,如果 PACK_ID 4 和 PACK_ID 6 可用,则使用 6

我想我们可以从这里开始。确保在 运行 之前初始化您的表。我假设#TIMEGAPS 有一个基于你的输出的权重列。

DECLARE 
        @Pack_id INT
    ,   @Weight_id INT
    ,   @mloop INT = 0 

DECLARE @possible TABLE ( 
        id  INT IDENTITY (1,1) 
    ,   pack_id     INT 
    ,   weight ) 


BEGIN_LABEL:

SELECT  TOP 1 @pack_id  = PACK_ID 
FROM #TIMEGAPS AS g
WHERE g.WEIGHT IS NULL 
ORDER BY PACK_ID ASC 

IF @pack_id IS NULL 
    BEGIN 
        PRINT 'Done'
        EXIT 
    END

INSERT INTO @possible (pack_id , weight ) 
SELECT PACK_ID , WEIGHT 
FROM #REALVALUES as r 
LEFT JOIN  #TIMEGAPS as g 
    ON g.WEIGHT = r.PACK_ID 
WHERE g.WEIGHT IS NULL 
ORDER BY ABS(@pack_id - PACK_ID) ASC , WEIGHT DESC

SELECT TOP 1 @Weight_id = weight 
FROM @possible 
ORDER BY id ASC 

IF (@Weight_id IS NULL)
    BEGIN 
            RAISERROR('No Weights available' , 18 , 1)
            EXIT 
    END

UPDATE #TIMEGAPS 
SET WEIGHT = @Weight_id  
WHERE PACK_ID = @Pack_id 

SET @mloop = @mloop + 1 

IF @mloop > 99 
    BEGIN 
        PRINT 'Hit Safety'
        EXIT 
    END

SELECT @Pack_id = NULL , @Weight_id = NULL;

DELETE @possible;

GOTO BEGIN_LABEL 

SELECT g.PACK_ID , g.Local_Time , r.WEIGHT 
FROM #TIMEGAPS AS g
INNER JOIN #REALVALUES AS r
 r.PACK_ID = g.WEIGHT;

我很确定 RAISERROR() 在 SQL 2008 中可以工作,但如果它们不工作,您可以用打印语句替换它们

是这样的吗?

它使用 row_number 距离。

SELECT 
 PACK_ID, Local_Time, WEIGHT
FROM (
  SELECT g.PACK_ID, g.Local_Time, v.WEIGHT, 
  ROW_NUMBER() OVER (PARTITION BY g.PACK_ID, g.Local_Time 
                     ORDER BY ABS(v.PACK_ID - g.PACK_ID), v.PACK_ID DESC) AS RN
  FROM #TIMEGAPS AS g
  JOIN #REALVALUES AS v ON v.Local_Time = g.Local_Time
) AS q
WHERE RN = 1
ORDER BY PACK_ID, Local_Time