Я собираюсь получить отчет о продажах за десять дней и хочу вернуть 0, если нет записей для каждого дня. - PullRequest
0 голосов
/ 25 сентября 2019
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[Sp_Rsv_DailyContractReport]
    @ContractDate datetime =null,  
    @RegisterUsersId varchar(32) = null

AS   

    Select    

    IsNull (SUM( c.Price) ,0) As 'TotalPrice', 
    IsNull(COUNT(c.[Id]) ,0) As 'ContractCount'     
    from Rsv_Contract as c

    where 
    c.ContractDate >= @ContractDate and  --'09/15/2019' ten day before till know
    c.RegisterUsersId = @RegisterUsersId and    
    c.contractstate in (1,2) and 
    c.ContractNumber!='0000000' and c.ContractNumber!='-1'

    Group by CAST(c.ContractDate AS DATE)   

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

Ответы [ 2 ]

2 голосов
/ 25 сентября 2019

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

    Declare @start Date, @end Date
    Select @start=DATEADD(DAY,-10,@ContractDate), @end=@ContractDate

    ;With ContractDates( ContractDate ) as
    (
        Select @start as ContractDate
            union all
        Select Cast(DATEADD(DAY,1,ContractDate) as DATE)
            from ContractDates
            where ContractDate < @end
    )
    Select 
    ISNull(ct.TotalPrice,0) As 'TotalPrice' ,IsNull(ct.ContractCount,0) AS 'ContractCount' 
    from ContractDates cd 
    left join 
    (  
        Select    
        IsNull (SUM( c.Price) ,0) As 'TotalPrice', 
        IsNull(COUNT(c.[Id]) ,0) As 'ContractCount'    
        CAST(c.ContractDate AS DATE)    
        from Rsv_Contract as c
        where 
        c.ContractDate between DATEADD(DAY,-10,@ContractDate) and @ContractDate and
        c.RegisterUsersId = @RegisterUsersId and    
        c.Contractstate in (1,2) and 
        c.ContractNumber!='0000000' and c.ContractNumber!='-1'
        Group by CAST(c.ContractDate AS DATE) 
    )ct on cd.ContractDate=ct.ContractDate
1 голос
/ 25 сентября 2019

Вы можете использовать простую функцию, подобную этой, чтобы сгенерировать нужную вам небольшую норму дат:

CREATE FUNCTION dbo.DatesBetween
(
    @StartDate date,
    @EndDate date 
)
RETURNS @Dates TABLE
(
    DateNumber int IDENTITY(1,1) PRIMARY KEY,
    DateValue date
)
AS
BEGIN
    DECLARE @CurrentValue date = @StartDate;

    WHILE @CurrentValue <= @EndDate 
    BEGIN
        INSERT @Dates (DateValue) VALUES (@CurrentValue);
        SET @CurrentValue = DATEADD(day, 1, @CurrentValue);
    END;

    RETURN;
END;
GO

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

CREATE PROCEDURE [dbo].[Sp_Rsv_DailyContractReport]
@ContractDate datetime =null,  
@RegisterUsersId varchar(32) = null
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;

    SELECT db.DateValue AS [Date],
           ISNULL(SUM(c.Price) , 0) AS TotalPrice, 
           ISNUll(COUNT(c.[Id]) ,0) AS ContractCount     
    FROM dbo.DatesBetween(@ContractDate, SYSDATETIME()) AS db
    LEFT OUTER JOIN dbo.Rsv_Contract as c
    ON db.DateValue = CAST(c.ContractDate AS date)
    WHERE c.RegisterUsersId = @RegisterUsersId 
    AND c.ContractState IN (1, 2)
    AND c.ContractNumber !='0000000' 
    AND c.ContractNumber != '-1'
    GROUP BY db.DateValue;  
END;
GO


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