Выберите первое ненулевое значение по дате для каждого столбца в нескольких строках - PullRequest
0 голосов
/ 07 февраля 2019

У меня есть таблица, подобная следующей:

+-------------------------+------+------+------+------+  
|          Date           |  A   |  B   |  C   |  D   |  
+-------------------------+------+------+------+------+  
| 2010-11-16 10:02:00.000 | 10   | NULL | NULL | NULL |  
| 2010-09-21 00:00:00.000 | 86   | 14   | NULL | 17   |  
| 2010-07-27 00:00:00.000 | 125  | 12   | NULL | 11   |  
| 2010-05-29 15:24:00.000 | NULL | NULL | 1250 | NULL |  
+-------------------------+------+------+------+------+  

Мне нужен запрос для извлечения первого ненулевого значения каждого столбца.Что-то вроде «вертикального слияния».

Желаемый результат будет:

+-------------------------+------+------+------+------+  
|          Date           |  A   |  B   |  C   |  D   |  
+-------------------------+------+------+------+------+  
| 2010-11-16 10:02:00.000 | 10   | 14   | 1250 | 17   |  
+-------------------------+------+------+------+------+ 

таблица упорядочена по дате (desc)
фактическая таблица имеет гораздо больше столбцов (40) и строки (до 5000)

Редактировать:

В моей фактической таблице гораздо больше столбцов и строк (скажем, около 40 столбцов и до 5000 строк),Я боюсь, что несколько запросов по порядку могут ухудшить производительность запроса.Однако, если не появится более чистое решение, я пойду на это.

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Вы можете попробовать что-то подобное, чтобы избежать заказа.Я знаю, что в начале довольно сложно определить 50 переменных, но вам не о чем беспокоиться позже.

declare @A int = (select top 1 A from #Table where A is not null)
declare @B int = (select top 1 B from #Table where B is not null)
declare @C int = (select top 1 C from #Table where C is not null)
declare @D int = (select top 1 D from #Table where D is not null)

select top 1 Date,@A,@B,@C,@D
from #Table 
0 голосов
/ 07 февраля 2019

Я не проверял это, но он выглядит достаточно злым:

with cte as (
    select date
         , a, max(case when a is not null then date end) over () as date_a
         , b, max(case when b is not null then date end) over () as date_b
         , c, max(case when c is not null then date end) over () as date_c
         , d, max(case when d is not null then date end) over () as date_d
    from t
)
select max(date) as date
     , min(case when date = date_a then a end) as a
     , min(case when date = date_b then b end) as b
     , min(case when date = date_c then c end) as c
     , min(case when date = date_d then d end) as d
from cte

Без оконных функций:

with cte as (
    select max(case when a is not null then date end) as date_a
         , max(case when b is not null then date end) as date_b
         , max(case when c is not null then date end) as date_c
         , max(case when d is not null then date end) as date_d
    from t
)
select max(date) as date
     , min(case when date = date_a then a end) as a
     , min(case when date = date_b then b end) as b
     , min(case when date = date_c then c end) as c
     , min(case when date = date_d then d end) as d
from t
cross join cte

Демонстрация на db <> fiddle

0 голосов
/ 07 февраля 2019

Это один из возможных подходов, если ваш заказ убывает на [Date] столбец:

Ввод:

CREATE TABLE #Table (
    [Date] datetime,
    A int,
    B int,
    C int,
    D int
)
INSERT INTO #Table
    ([Date], A, B, C, D)
VALUES
    ('2010-11-16T10:02:00.000', 10  , NULL, NULL, NULL),  
    ('2010-09-21T00:00:00.000', 86  , 14  , NULL, 17  ),  
    ('2010-07-27T00:00:00.000', 125 , 12  , NULL, 11  ),  
    ('2010-05-29T15:24:00.000', NULL, NULL, 1250, NULL)  

Заявление:

SELECT 
    [Date] = (SELECT TOP 1 [Date] FROM #Table WHERE [Date] IS NOT NULL ORDER BY [Date] DESC),
    [A] = (SELECT TOP 1 [A] FROM #Table WHERE [A] IS NOT NULL ORDER BY [Date] DESC),
    [B] = (SELECT TOP 1 [B] FROM #Table WHERE [B] IS NOT NULL ORDER BY [Date] DESC),
    [C] = (SELECT TOP 1 [C] FROM #Table WHERE [C] IS NOT NULL ORDER BY [Date] DESC),
    [D] = (SELECT TOP 1 [D] FROM #Table WHERE [D] IS NOT NULL ORDER BY [Date] DESC)

Выход:

Date                    A   B   C       D
2010-11-16 10:02:00.000 10  14  1250    17

Обновление - еще один возможный подход с использованием агрегатных функций:

;WITH DatesCTE AS (
    SELECT
        [Date] = MAX([Date]), 
        [DateA] = MAX(CASE WHEN A IS NOT NULL THEN [Date] END),
        [DateB] = MAX(CASE WHEN B IS NOT NULL THEN [Date] END),
        [DateC] = MAX(CASE WHEN C IS NOT NULL THEN [Date] END),
        [DateD] = MAX(CASE WHEN D IS NOT NULL THEN [Date] END)
    FROM #Table
)
SELECT 
    d.[Date],
    A = MAX(CASE WHEN t.[Date] = d.[DateA] THEN A END),
    B = MAX(CASE WHEN t.[Date] = d.[DateB] THEN B END),
    C = MAX(CASE WHEN t.[Date] = d.[DateC] THEN C END),
    D = MAX(CASE WHEN t.[Date] = d.[DateD] THEN D END)
FROM DatesCTE d
CROSS APPLY #Table t
GROUP BY d.[Date]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...