Home > Net >  Return 0 values where corresponding type is missing
Return 0 values where corresponding type is missing

Time:01-11

I need a select query where I get amount of visits, type of visit to sort it and in which dates this happend.

My problem is that I dont get 0s at times where there are no visits.

I am using this code:

        SELECT COUNT(*) AS numberOfVisits,
               CONVERT(DATE, CONVERT(VARCHAR(10), CAST(dateOfVisit AS DATE), 121)) AS typeOfVisit,
               typeOfVisit
        FROM WEB
        WHERE dateOfVisit >= '1-1-2021'
        AND dateOfVisit <= '1-31-2021'
        GROUP BY CAST(dateOfVisit AS DATE), typeOfVisit
        ORDER BY CAST(dateOfVisit AS DATE)

/*i am converting and casting the date for other reasons that i need in 
my API/frontend and i also get the condition of date from api 1-1-2021 
and 1-31-2021 are just for sample*/

and with this i get the following results: https://imgur.com/a/o3c9A2p

The columns Follow as: numberOfVisits | dateOfVisit | typeOfVisit

As you can see I have 4 types. The first 3 rows contain types 2,3,4 but not 1; I want to have an extra row here with value 0, same date and type 1.

The actual value 0 is also not written in the database and neither is null

The desired result would be like this:

0   2021-01-04  1
1   2021-01-04  2
10  2021-01-04  3
2   2021-01-04  4

and if the result would only show that there were visits of type 2 then it would be something like this:

0   2021-01-04  1
1   2021-01-04  2
0   2021-01-04  3
0   2021-01-04  4

CodePudding user response:

You can't count if there is no table record of date. You need to have calendar table with every date to start select from then left join your visit table and count.

It would be something like this:

if OBJECT_ID('tempdb..#Calendar') is not null drop table #Calendar

create table #Calendar (adDate date)

declare @dDate date = '2021-01-01'
while @dDate <= '2021-01-31'
begin
    insert into #Calendar (adDate)
    select @dDate

    set @dDate = dateadd(DAY, 1, @dDate)
end

select
    c.adDate,
    w.typeOfVisit,
    COUNT(w.visit) as VisitCount

from #Calendar c
left join web w on w.dateOfVisit = c.adDate
group by 
    c.adDate,
    w.typeOfVisit
order by
    c.adDate

If you want to have 0 visits by type also, not just by day then you can do it like this:

if OBJECT_ID('tempdb..#Calendar') is not null drop table #Calendar

create table #Calendar (adDate date, anTypeOfVisit int)

declare 
    @dDate date = '2021-01-01',
    @nTypeOfVisit int
while @dDate <= '2021-01-31'
begin
    set @nTypeOfVisit = 1
    while @nTypeOfVisit <=4
    begin
        insert into #Calendar (adDate, anTypeOfVisit)
        select @dDate, @nTypeOfVisit

        set @nTypeOfVisit = @nTypeOfVisit   1
    end

    set @dDate = dateadd(DAY, 1, @dDate)
end

select
    c.adDate,
    c.anTypeOfVisit,
    COUNT(w.dateofvisit) as VisitCount

from #Calendar c
left join web w on w.dateOfVisit = c.adDate and w.typeofvisit = c.anTypeOfVisit

group by 
    c.adDate,
    c.anTypeOfVisit
order by
    c.adDate,
    c.anTypeOfVisit

CodePudding user response:

You need to create a table that contains a row for each visit type for each date. Then do a left join to bring in the counts from your actual data

DROP TABLE IF EXISTS #Visit 
CREATE TABLE #Visit (ID INT IDENTITY(1,1) ,DateOfVisit Date,TypeOfVisit int)
INSERT INTO #Visit
VALUES ('2021-01-04',2),('2021-01-04',3),('2021-01-04',3),('2021-01-04',4);

WITH cte_DistinctVisitDate AS (
    SELECT DateOfVisit
    FROM #Visit
    WHERE DateOfVisit BETWEEN '2020-01-04' AND '2021-01-04' /*Always use YYYY-MM-DD for params as it is culture-agnostic*/
    GROUP BY DateOfVisit
),
cte_TypePerDate AS (
    /*One row for each type on each visit date*/
    SELECT DateOfVisit,TypeOfVisit
    FROM cte_DistinctVisitDate
    CROSS JOIN (VALUES (1),(2),(3),(4)) AS B(TypeOfVisit) /*I am hard coding raw data, but you should use lookup table that contains each visit type*/
),
cte_VisitCount  AS (
    /*Actual counts, but only lists visit types with visits*/
    SELECT DateOfVisit,TypeOfVisit,VisitCnt = COUNT(*)
    FROM #Visit
    GROUP BY DateOfVisit,TypeOfVisit
)

SELECT A.DateOfVisit,A.TypeOfVisit,VisitCnt = ISNULL(B.VisitCnt,0)
FROM cte_TypePerDate AS A
LEFT JOIN cte_VisitCount AS B
    ON A.DateOfVisit = B.DateOfVisit
    AND A.TypeOfVisit = B.TypeOfVisit
  •  Tags:  
  • Related