SQL-запрос для добавления пропущенных значений для поля между двумя датами? - PullRequest
0 голосов
/ 21 августа 2010

Хорошо, у меня есть эти две таблицы -

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

Поэтому, когда я пытаюсь составить список между двумя датами, скажем, с 10 декабря 2009 года по 30 октября 2009 года. Должен отображаться список вроде -

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 ]

2 голосов
/ 21 августа 2010

Я включил здесь только параметры, чтобы проиллюстрировать, где нужно указать самую раннюю дату и самую позднюю дату. Эти два значения могут быть выведены из ваших данных при необходимости.

Хитрость заключается в том, чтобы преобразовать исходные данные в диапазоны с начальной и конечной датой. Затем мы генерируем календарную таблицу последовательных дат, охватывающую требуемый период времени, и присоединяемся к нашим диапазонам, чтобы определить результаты.

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 голос
/ 21 августа 2010
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]
0 голосов
/ 21 августа 2010

Спасибо всем за ответы, вот как я это сделал -

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)
0 голосов
/ 21 августа 2010
Select Weight, Date 
from Dimdate d left outer join BioUser b
on b.DateAdded= d.Date

должен возвращать ноль для веса, если для этого дня нет значения веса.

HTH

вам нужно извлечь дату из таблицы dimDate, а не bioUser, которая может бытьпустой

0 голосов
/ 21 августа 2010

Вы должны начать с таблицы DimDate и JOIN BioUser для этого:

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

Это будет отображать NULL для любой даты, которая не была заполнена в таблице BioUser.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...