Microsoft SQL Server에서 위쪽 방향으로 NULL을 채우는 방법을 파악하려고합니다. 이것은 오라클에서 매우 간단하지만 사장님은 그것을 위해 가지 않았습니다. google 검색의 6 시간 후에 나는 마침내 게시하기로 결정했다. 결과 집합에서 Microsoft SQL Server에는 현재 수행중인 것보다 양방향으로 null 값을 채우는 더 좋은 방법이 있습니까?
....VALUE 가능한 모든 날짜의 시간과 우리의 시간 스탬프 데이터입니다.
VALUE2는 Google의 내림 값 하향 조정 방법입니다.
VALUE3은 Google의 상한값 입력 방법입니다.
이 가짜 시시한 표를 감안할 때.
-- Test Data & Table
DECLARE @TEST001 TABLE
(TIME_STAMP datetime,
TagA integer,
TagB integer,
TagC integer)
-- Insert test Values
INSERT INTO @TEST001
VALUES
('2017-01-21 00:01:00.042', NULL, NULL, 87),
('2017-01-21 00:04:10.155', NULL, 1239, NULL),
('2017-01-21 00:04:10.959', NULL, NULL, 86),
('2017-01-21 00:06:49.401', NULL, 1240, NULL),
('2017-01-21 00:06:59.301', NULL, 1239, NULL),
('2017-01-21 00:07:10.124', 108, NULL, NULL),
('2017-01-21 00:12:11.789', 109, NULL, NULL),
('2017-01-21 00:16:12.190', 108, NULL, NULL),
('2017-01-21 00:16:13.987', 107, NULL, NULL),
('2017-01-21 00:17:31.410', NULL, 1260, NULL),
('2017-01-21 00:17:32.511', NULL, 1261, 87),
('2017-01-21 00:17:32.966', NULL, 1262, NULL)
우리의 가짜 시시한 테이블에서 TagA를 쿼리하는이 쿼리를 감안할 때. 오늘 매우 큰 데이터 세트와 함께 놀았 이것이 가장 빠른 일이 될 것으로
:
-- Start of Query used in VBS ADODB CONN.
declare @s datetime
declare @e datetime
set @s = '2017-01-21 00:00:00'
set @e = '2017-01-21 23:59:59'
;
-- We need to get all intervals between our two dates.
WITH ALL_INTERVALS AS (
SELECT TOP (datediff(mi,@s,@e))
TIMES = dateadd(mi,CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id])),@s)
FROM sys.all_objects AS s1
CROSS JOIN
sys.all_objects AS s2
),
-- We need to include both our real data and all possible intervals.
ALL_TIMES AS (
SELECT
Time_Stamp as TIMES,
TagA AS VALUE
FROM @TEST001 H
WHERE Time_Stamp BETWEEN @s and @e
UNION ALL
SELECT
TIMES AS TIMES,
NULL AS VALUE
FROM ALL_INTERVALS
),
-- We need to find the real first value and fill all nulls with this value until we hit a new value.
FILL_DOWN AS (SELECT
TIMES,
VALUE,
ISNULL(VALUE, (SELECT TOP 1 VALUE FROM ALL_TIMES WHERE TIMES < AT.TIMES AND VALUE IS NOT NULL ORDER BY TIMES DESC)) AS VALUE2
FROM ALL_TIMES AT
),
-- Our fill up method does not work if our first set of values is null. UGH, this does not work either....crap. It fills our first set
-- With our last real value....
FILL_UP AS (
SELECT
TIMES,
VALUE,
VALUE2,
ISNULL(VALUE2, (SELECT TOP 1 VALUE2 FROM FILL_DOWN WHERE TIMES > FD.TIMES AND VALUE2 IS NOT NULL ORDER BY TIMES DESC)) AS VALUE3
FROM FILL_DOWN FD
)
SELECT *
FROM FILL_UP
ORDER BY TIMES ASC
는
TIMES VALUE VALUE2 VALUE3
2017-01-2100:01:00.000 NULL NULL 107 <---------- This should be 108 from our fake crappy table.
2017-01-2100:01:00.043 NULL NULL 107
2017-01-2100:02:00.000 NULL NULL 107
2017-01-2100:03:00.000 NULL NULL 107
2017-01-2100:04:00.000 NULL NULL 107
2017-01-2100:04:10.157 NULL NULL 107
2017-01-2100:04:10.960 NULL NULL 107
2017-01-2100:05:00.000 NULL NULL 107
2017-01-2100:06:00.000 NULL NULL 107
2017-01-2100:06:49.400 NULL NULL 107
2017-01-2100:06:59.300 NULL NULL 107
2017-01-2100:07:00.000 NULL NULL 107
2017-01-2100:07:10.123 108 108 108
2017-01-2100:08:00.000 NULL 108 108
2017-01-2100:09:00.000 NULL 108 108
2017-01-2100:10:00.000 NULL 108 108
2017-01-2100:11:00.000 NULL 108 108
2017-01-2100:12:00.000 NULL 108 108
2017-01-2100:12:11.790 109 109 109
2017-01-2100:13:00.000 NULL 109 109
2017-01-2100:14:00.000 NULL 109 109
2017-01-2100:15:00.000 NULL 109 109
2017-01-2100:16:00.000 NULL 109 109
2017-01-2100:16:12.190 108 108 108
2017-01-2100:16:13.987 107 107 107
2017-01-2100:17:00.000 NULL 107 107
2017-01-2100:17:31.410 NULL 107 107
2017-01-2100:17:32.510 NULL 107 107
2017-01-2100:17:32.967 NULL 107 107
2017-01-2100:18:00.000 NULL 107 107
2017-01-2100:19:00.000 NULL 107 107
2017-01-2100:20:00.000 NULL 107 107
2017-01-2100:21:00.000 NULL 107 107
2017-01-2100:22:00.000 NULL 107 107
2017-01-2100:23:00.000 NULL 107 107
2017-01-2100:24:00.000 NULL 107 107
2017-01-2100:25:00.000 NULL 107 107
2017-01-2100:26:00.000 NULL 107 107
편집 결과. 정확히 내가 원하는 순간을 정확하게 수행합니다. 이 작은 테이블에서는 속도 차이를 볼 수 없지만 큰 데이터 세트로 1 초 및 24 분이 많이 걸립니다! 도와 주신 모든 분들께 진심으로 감사드립니다.
-- Test Data & Table
DECLARE @TEST001 TABLE
(TIME_STAMP datetime,
TagA integer,
TagB integer,
TagC integer)
-- Insert test Values
INSERT INTO @TEST001
VALUES
('2017-01-21 00:01:00.042', NULL, NULL, 87),
('2017-01-21 00:04:10.155', NULL, 1239, NULL),
('2017-01-21 00:04:10.959', NULL, NULL, 86),
('2017-01-21 00:06:49.401', NULL, 1240, NULL),
('2017-01-21 00:06:59.301', NULL, 1239, NULL),
('2017-01-21 00:07:10.124', 108, NULL, NULL),
('2017-01-21 00:12:11.789', 109, NULL, NULL),
('2017-01-21 00:16:12.190', 108, NULL, NULL),
('2017-01-21 00:16:13.987', 107, NULL, NULL),
('2017-01-21 00:17:31.410', NULL, 1260, NULL),
('2017-01-21 00:17:32.511', NULL, 1261, 87),
('2017-01-21 00:17:32.966', NULL, 1262, NULL)
-- Start of Query used in VBS ADODB CONNN
declare @s datetime
declare @e datetime
set @s = '2017-01-01 00:00:00'
set @e = '2017-01-31 23:59:59'
;
WITH ALL_INTERVALS
AS (SELECT TOP (datediff(mi,@s,@e))
TIMES = dateadd(mi,CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id])),@s),
NULL AS VALUE
FROM sys.all_objects AS s1
CROSS JOIN
sys.all_objects AS s2
),
ALL_TIMES
AS (SELECT
H.TIME_STAMP as TIMES,
TagA AS VALUE
FROM @TEST001 H
WHERE TIME_STAMP BETWEEN @s and @e
UNION ALL
SELECT
AI.TIMES AS TIMES,
AI.VALUE AS VALUE
FROM ALL_INTERVALS AI
),
-- JUST INCASE OUR REAL TIME == INTERVAL TIME exactly.
FILL_ACCROSS AS(SELECT TIMES AS TIMES,
ISNULL(AT.VALUE, (SELECT TOP 1 VALUE FROM ALL_TIMES WHERE TIMES = AT.TIMES AND VALUE IS NOT NULL ORDER BY TIMES ASC)) AS VALUE
FROM ALL_TIMES AT
),
-- FILL UP AND FILL DOWN.
FILL_UP_DOWN AS (SELECT
TIMES,
VALUE,
ISNULL(FA.VALUE, (SELECT TOP 1 VALUE FROM ALL_TIMES WHERE TIMES > FA.TIMES AND VALUE IS NOT NULL ORDER BY TIMES ASC)) AS VALUE2,
ISNULL(FA.VALUE, (SELECT TOP 1 VALUE FROM ALL_TIMES WHERE TIMES < FA.TIMES AND VALUE IS NOT NULL ORDER BY TIMES DESC)) AS VALUE3
FROM FILL_ACCROSS FA
)
--Just a nice display of what is going on.
select FD.TIMES,
FD.VALUE,
FD.VALUE2,
FD.VALUE3,
CASE
WHEN FD.VALUE3 IS NULL THEN (FD.VALUE2)
ELSE (FD.VALUE3)
END AS VALUE4
FROM FILL_UP_DOWN FD order by TIMES ASC
그룹화이 시도. 샘플 데이터를 줄이고 원하는 결과를 추가 할 수 있습니까? –
상관 관계 서브 쿼리에서'DESC'에서'ASC'까지'VALUE3'을 얻기 위해 순서를 바꾸면 원하는 결과를 얻을 수 있습니다. 현재는 주어진 날짜 이후 마지막 Null이 아닌 값을 찾고있는 반면, 처음에는 Null이 아닌 값을 원합니다. – GarethD
DESC를 FILL_DOWN 순으로 놓으십시오. – Serg