SQL Query用于在两个日期之间添加字段的缺失值?

时间:2010-08-20 20:56:33

标签: sql sql-server-2008

好的,我有这两张桌子 -

BioUser- UserId,Weight,DateAdded
DimDate-Date // It has basically all the dates for any period..its basically a table with all dates till 2050

现在,BioUser表中有用户体重的条目,但不是每天都有,但每当他们输入体重时。所以我想基本建立一个BioUser中所有缺失日期的日期和重量值列表。为了更好地解释自己,这是一个例子 -

BioUser -

UserId Weight  DateAdded
 1      178    10/12/2009
 1      175    10/18/2009
 1      172    10/27/2009

因此,当我试图在2009年12月10日到2009年10月30日之间的两个日期之间建立一个列表。它应该显示一个像 -

这样的列表
Weight Date

178  10/12/2009
178  10/13/2009
178  10/14/2009
178  10/15/2009
178  10/16/2009
178  10/17/2009
175  10/18/2009
175  10/19/2009
175  10/20/2009
175  10/21/2009
175  10/22/2009
175  10/23/2009
175  10/24/2009
175  10/25/2009
175  10/26/2009
172  10/27/2009
172  10/28/2009
172  10/29/2009
172  10/30/2009

我有这样的问题 -

Select Weight,DateAdded from BioUser join Dimdate on BioUser.DateAdded=Dimdate.Date

但上述方法无论如何都不起作用我希望从BioUser获得最近的重量输入,并且只有一个条目,因为BioUser表可以有一天的多个条目。任何人都可以帮助我...

5 个答案:

答案 0 :(得分:2)

我在此处仅包含参数,以说明您需要指定最早日期和最新日期的位置。如有必要,可以从您的数据中推导出这两个值。

这里的技巧是将源数据转换为具有开始和结束日期的范围。然后,我们生成一个包含所需时间段的连续日期的日历表,并加入我们的范围以确定结果。

Declare @MinDate datetime;
Declare @MaxDate datetime;

Set @MinDate = '2009-10-12';
Set @MaxDate = '2009-10-30';

With BioUser As
    (
    Select 1 As UserId, 178 As Weight, '2009-10-12' As DateAdded
    Union All Select 1, 175, '2009-10-18'   
    Union All Select 1, 172, '2009-10-27'   
    )
    , Calendar As
    (
    Select @MinDate As [Date]
    Union All
    Select DateAdd(d,1,[Date])
    From Calendar
    Where [Date] < @MaxDate
    )
    , BioUserDateRanges As
    (
    Select B1.UserId, B1.Weight, B1.DateAdded As StartDate, Coalesce(Min(B2.DateAdded),@MaxDate) As EndDate
    From BioUser As B1
        Left Join BioUser As B2
            On B2.UserId = B1.UserId
                And B2.DateAdded > B1.DateAdded
    Group By B1.UserId, B1.Weight, B1.DateAdded
    )
Select BR.Weight, C.[Date]
From Calendar As C
    Join BioUserDateRanges As BR
        On BR.StartDate <= C.[Date]
            And BR.EndDate >= C.[Date]
Option (MaxRecursion 0);

答案 1 :(得分:1)

WITH Dimdate  As
(
SELECT DATEADD(DAY,-number,CAST('2009-12-31' AS DATETIME)) AS [Date]
from master.dbo.spt_values where type='p'
),
BioUser  AS
(SELECT 1 AS [UserId], 178 AS [Weight], CAST('20091012' AS DATETIME) AS DateAdded
UNION ALL
SELECT 1 AS [UserId], 175 AS [Weight], CAST('20091018' AS DATETIME)
UNION ALL
SELECT 1 AS [UserId], 172 AS [Weight], CAST('20091027' AS DATETIME)
),
NumberedT AS
(
SELECT [UserId],[Weight],DateAdded, 
       ROW_NUMBER() OVER (PARTITION BY [UserId] ORDER BY DateAdded) AS RN
FROM BioUser 
)
SELECT  
     ISNULL(T1.[UserId], T2.[UserId]) [UserId], 
     ISNULL(T1.Weight, T2.Weight) [Weight], 
     Dimdate.[Date]
 FROM NumberedT T1
FULL OUTER JOIN NumberedT T2 ON T2.RN = T1.RN+1 AND T2.[UserId]= T1.[UserId]
INNER JOIN Dimdate ON 
    (Dimdate.[Date] >= ISNULL(T1.DateAdded, T2.DateAdded) 
        AND Dimdate.[Date]< T2.DateAdded)
OR
    (T2.DateAdded IS NULL AND Dimdate.[Date]=T1.DateAdded)
ORDER BY Dimdate.[Date]

答案 2 :(得分:0)

您应该从DimDate表和JOIN BioUser开始:

SELECT u.Weight, u.DateAdded
FROM DimDate d
    LEFT OUTER JOIN d.Date = u.DateAdded

然后,对NULL表中未填充的任何日期显示BioUser

答案 3 :(得分:0)

Select Weight, Date 
from Dimdate d left outer join BioUser b
on b.DateAdded= d.Date
如果那天没有重量值,

应该返回重量的空值。

HTH

你需要从dimDate表中提取日期,而不是bioUser,这可能是null

答案 4 :(得分:0)

感谢大家的回答,这就是我做到的 -

SELECT    
        (SELECT TOP (1) Weight
         FROM BioUser AS b
         WHERE (CAST(DateTested AS Date) <= k.Date) AND (UserId= @UserId)
         ORDER BY DateTested DESC) AS Weight, Date AS DateTested
FROM     DimDate AS k
WHERE     (Date BETWEEN @StartDate AND @EndDate)