将Null值替换为同一个表中的数据

时间:2016-05-31 12:50:02

标签: sql sql-server

我正在计算累积计数(两张表中的2条线索)。我设法得到以下结果。现在我想要像这样替换NULL值: 如果它是表的第一行,那么我需要插入第一个not null值。对于其余的行,我需要插入当前行之前的最后一个非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

通缉结果:

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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