2016-05-31 4 views
0

Я вычисляю совокупный счет (2 значения из двух таблиц). Мне удалось получить следующий результат. Теперь я хочу заменить значения NULL следующим образом: Если его первая строка таблицы, тогда мне нужно вставить первое не пустое значение. Для остальных строк мне нужно вставить последнее ненулевое значение, которое появляется перед текущей строкой. Есть ли способ достичь этого?Заменить Нулевые значения данными из той же таблицы

Date     | Count1 | Count2 
2016-01-01 00:00:00.000 | NULL | 52 
2016-01-02 00:00:00.000 | NULL | 54 
2016-01-05 00:00:00.000 | 62  | 55 
2016-01-08 00:00:00.000 | NULL | 56 
2016-01-11 00:00:00.000 | 91  | NULL 
2016-01-12 00:00:00.000 | 92  | 59 

Wanted Результат:

Date     | Count1 | Count2 
2016-01-01 00:00:00.000 | 62  | 52 
2016-01-02 00:00:00.000 | 62  | 54 
2016-01-05 00:00:00.000 | 62  | 55 
2016-01-08 00:00:00.000 | 62  | 56 
2016-01-11 00:00:00.000 | 91  | 56 
2016-01-12 00:00:00.000 | 92  | 59 

Запрос я использовал для создания этого результата:

declare @DateCountOpportunities table(d int primary key, c int, cr int) 
insert into @DateCountOpportunities 
select 
     datediff(d, 0, IsNull(CreationDate, StartDate)) as d, 
     count(*) as OpportunitiesCount, 
     0 
     from [JobOpportunities] 
     group by datediff(d, 0, IsNull(CreationDate, StartDate)) 

declare @rt int = 0 
declare @anchor int 

update @DateCountOpportunities set 
     @rt = cr = @rt + c, 
     @anchor = d 
option (maxdop 1) 

declare @DateCountRestaurants table(d int primary key, c int, cr int) 
insert into @DateCountRestaurants 
select 
     datediff(d, 0, CreatedAt) as d, 
     count(*) as RestaurantsCount, 
     0 
from [Restaurants] 
group by datediff(d, 0, CreatedAt) 

declare @rtRes int = 0 
declare @anchorRs int 

update @DateCountRestaurants set 
     @rtRes = cr = @rtRes + c, 
     @anchorRs = d 
option (maxdop 1) 

Declare @ResultTable table(DateOpportunities DateTime, DateRestaurant DateTime, RestaurantsCount int, OpportunitiesCount int) 
insert into @ResultTable 

select isnull(DateOpportunities, DateRestaurants) DateOpportunities, isnull(DateRestaurants, DateOpportunities) DateRestaurant, RestaurantsCount, OpportunitiesCount from 
(
    select 
      dateadd(d, d, 0) as DateRestaurants, 
      cr as RestaurantsCount 
    from @DateCountRestaurants 

) Rs 

full outer join 
(
    select 
      dateadd(d, d, 0) as DateOpportunities, 
      cr as OpportunitiesCount 
    from @DateCountOpportunities 

)Opp 
on Rs.DateRestaurants = Opp.DateOpportunities 
order by DateOpportunities 


select DateOpportunities as [Date], 
RestaurantsCount 
, 
OpportunitiesCount from @ResultTable 
+5

Это похоже на такие вещи, которая лучше решена путем модификации исходный запрос, который дает результат, вместо того, чтобы брать то, что показано здесь как заданное и накладывать сверху. Каковы ваши базовые данные и каков ваш текущий запрос? –

+0

Если вы делаете кумулятивный счет, я считаю, что ваш ответ лежит в запросе, используемом для генерации выводимого вами вывода. То, что вы хотите сделать, возможно, но может усложниться и, скорее всего, не понадобится. Можете ли вы опубликовать этот запрос? –

+0

@JeroenMostert это сложный запрос, проблема в том, что я получаю кумулятивный счет из двух отдельных таблиц. Я отправлю запрос, если вы хотите – Kira

ответ

1

Это немного устремился ответ, но я надеюсь, что он все еще помогает. В приведенном ниже запросе будут обновлены все записи только для одного столбца, поэтому вам может потребоваться повторить логику для второго столбца. Вероятно, есть способ изменить эту логику так, чтобы она обрабатывала как Count1, так и Count2 в одном и том же запросе (т. Е. Не требовала нескольких операторов UPDATE), но сейчас у меня недостаточно времени для работы с этим решением.

Я проверил следующие с ситуациями, когда NULL в первом ряду (ов), строк центра и в последнем ряду с успехом:

CREATE TABLE #counting ([Date] DATETIME, Count1 INT, Count2 INT) 
INSERT INTO #counting 
SELECT '2016-01-01', NULL, 52 UNION 
SELECT '2016-01-02', NULL, 54 UNION 
SELECT '2016-01-05', 62, 55 UNION 
SELECT '2016-01-08', NULL, 56 UNION 
SELECT '2016-01-11', 91, NULL UNION 
SELECT '2016-01-12', 92, 59 UNION 
SELECT '2016-01-13', NULL, 56 


UPDATE 
    #counting 
SET 
    Count1 = rangeValue 
FROM 
    (
    SELECT * FROM 
    (
     SELECT TOP 1 
     firstDate, 
     firstValue.[Date] AS lastDate, 
     firstValue.Count1 AS rangeValue 
     FROM 
     #counting AS firstValue, 
     (SELECT MIN([Date]) AS firstDate FROM #counting WHERE Count1 IS NULL) AS firstDate 
     WHERE 
     Count1 IS NOT NULL AND 
     firstDate < firstValue.[Date] 
     ORDER BY 
     [Date] 
    ) AS a 
    UNION 
    SELECT 
     firstValueRecord.[Date] AS firstDate, 
     lastNullRecord.[Date] AS lastDate, 
     MAX(firstValueRecord.Count1) AS rangeValue 
    FROM 
     #counting AS firstValueRecord, 
     #counting AS nonNullRecords, 
     #counting AS lastNullRecord 
    WHERE 
     firstValueRecord.Count1 IS NOT NULL AND 
     nonNullRecords.Count1 IS NOT NULL AND 
     lastNullRecord.Count1 IS NULL AND 
     lastNullRecord.[Date] > nonNullRecords.[Date] AND 
     nonNullRecords.[Date] >= firstValueRecord.[Date] 
    GROUP BY 
     lastNullRecord.[Date], 
     firstValueRecord.[Date] 
    HAVING 
     COUNT(DISTINCT nonNullRecords.[Date]) = 1 
) AS a 
WHERE 
    Count1 IS NULL AND 
    [Date] BETWEEN firstDate AND lastDate 
0

Начиная с SQL Server 2012 можно использовать SUM()OVER(... ORDER BY ...) для вычисления текущих итогов. Пример:

SELECT *, SUM(t.Amount) OVER(ORDER BY t.ActionDate) AS RunningTotal 
FROM (VALUES 
    ('2016-01-01 00:00:00.000', 62), 
    ('2016-01-02 00:00:00.000', 0), 
    ('2016-01-05 00:00:00.000', 0), 
    ('2016-01-08 00:00:00.000', 0), 
    ('2016-01-11 00:00:00.000', 29), 
    ('2016-01-12 00:00:00.000', 0) 
) t(ActionDate, Amount) 

Результаты:

ActionDate    Amount  RunningTotal 
----------------------- ----------- ------------ 
2016-01-01 00:00:00.000 62   62 
2016-01-02 00:00:00.000 0   62 
2016-01-05 00:00:00.000 0   62 
2016-01-08 00:00:00.000 0   62 
2016-01-11 00:00:00.000 29   91 
2016-01-12 00:00:00.000 0   91 

Это означает, что начальное T-SQL партии можно упростить следующим образом:

SELECT 
    ISNULL(b.ActionDate, d.ActionDate) AS ActionDate, 
    b.RunningTotal1, 
    d.RunningTotal2 
FROM 
(
    SELECT b.ActionDate, SUM(b.Amount) OVER(ORDER BY b.ActionDate) AS RunningTotal1 
    FROM (
     SELECT t.ActionDate, SUM(t.Amount) AS Amount 
     FROM dbo.FirstTable t 
     GROUP BY t.ActionDate 
     UNION ALL 
     SELECT DISTINCT t.ActionDate, NULL AS Amount 
     FROM dbo.SeconTable t 
     WHERE NOT EXISTS (SELECT * FROM dbo.FirstTable x WHERE x.ActionDate = t.ActionDate) 
    ) a 
) AS b 
INNER JOIN 
(
    SELECT d.ActionDate, SUM(d.Amount) OVER(ORDER BY d.ActionDate) AS RunningTotal2 
    FROM (
     SELECT DISTINCT t.ActionDate, NULL AS Amount 
     FROM dbo.FirstTable t 
     WHERE NOT EXISTS (SELECT * FROM dbo.SecondTable x WHERE x.ActionDate = t.ActionDate) 
     UNION ALL 
     SELECT t.ActionDate, SUM(t.Amount) AS Amount 
     FROM dbo.SeconTable t 
     GROUP BY t.ActionDate 
    ) c 
) AS d 
ON b.ActionDate = d.ActionDate 
+0

Примечание: я не тестировал это решение. –

Смежные вопросы