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 权重信息:
- 使用最接近的 package_id 可用,即。对于 package_id 1 如果可用则使用 2,如果不可用则使用 3 etc
- 如果只有一个重量可用,请使用它来弥补所有缺失的 package_id 的
- 如果有两个权重可用,请使用较高的一个,即。对于 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
我有两个 tables:table 1 a package_id 和一个时间戳列,我没有可用的重量信息,table 2 a package_id、时间戳和权重列,我确实有信息。
我要做的是根据 table 2 使用以下限制填写 table 1 权重信息:
- 使用最接近的 package_id 可用,即。对于 package_id 1 如果可用则使用 2,如果不可用则使用 3 etc
- 如果只有一个重量可用,请使用它来弥补所有缺失的 package_id 的
- 如果有两个权重可用,请使用较高的一个,即。对于 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