简体   繁体   中英

Pivoting unique users for each month, each year

I'm learning about PIVOT function and I want to try it in my DB, in the table DDOT I have events (rows) made by users during X month Y year in the YYYYMM format.

id_ev iddate id_user ...
------------------------
1     201901 321
2     201902 654
3     201903 987
4     201901 321
5     201903 987

I'm basing my query on the MS Documentation and I'm not getting errors but I'm not able to fill it with the SUM of those unique events (users). In simple words I want to know how many users (unique) checked up each month (x axis) in the year (y axis). However, I'm getting NULL as result

YYYY    jan     feb     mar
----------------------------
2019    NULL    NULL    NULL

I'm expecting a full table with what I mentionted before.

YYYY    jan     feb     mar
----------------------------
2019    2       1       1

In the code I've tried with different aggregate functions but this block is the closest to a result from SQL.

CREATE TABLE ddot
(
 id_ev   int NOT NULL ,
 iddate  int NOT NULL ,
 id_user int NOT NULL 

);

INSERT INTO DDOT
(
 [id_ev], [iddate], [id_user]
)
VALUES
(
 1, 201901, 321
),
(
 2, 201902, 654
),
(
 3, 201903, 987
),
(
 4, 201901, 321
),
(
 5, 201903, 987
)
GO

SELECT *
FROM (
        SELECT COUNT(DISTINCT id_user) [TOT],
                DATENAME(YEAR, CAST(iddate+'01' AS DATETIME)) [YYYY], --concat iddate 01 to get full date
                DATENAME(MONTH, CAST(iddate+'01' AS DATETIME)) [MMM]

        FROM DDOT
        GROUP BY DATENAME(YEAR, CAST(iddate+'01' AS DATETIME)),
                DATENAME(MONTH, CAST(iddate+'01' AS DATETIME))
) AS DOT_COUNT
PIVOT(
        SUM([TOT])
        FOR MMM IN (jan, feb, mar)
) AS PVT

Ideally you should be using an actual date in the iddate column, and not a string (number?). We can workaround this using the string functions:

SELECT
    CONVERT(varchar(4), LEFT(iddate, 4)) AS YYYY,
    COUNT(CASE WHEN CONVERT(varchar(2), RIGHT(iddate, 2)) = '01' THEN 1 END) AS jan,
    COUNT(CASE WHEN CONVERT(varchar(2), RIGHT(iddate, 2)) = '02' THEN 1 END) AS feb,
    COUNT(CASE WHEN CONVERT(varchar(2), RIGHT(iddate, 2)) = '03' THEN 1 END) AS mar,
    ...
FROM DDOT
GROUP BY
    CONVERT(varchar(4), LEFT(iddate, 4));

Note that if the iddate column already be text, then we can remove all the ugly calls to CONVERT above:

SELECT
    LEFT(iddate, 4) AS YYYY,
    COUNT(CASE WHEN RIGHT(iddate, 2) = '01' THEN 1 END) AS jan,
    COUNT(CASE WHEN RIGHT(iddate, 2) = '02' THEN 1 END) AS feb,
    COUNT(CASE WHEN RIGHT(iddate, 2) = '03' THEN 1 END) AS mar,
    ...
FROM DDOT
GROUP BY
    LEFT(iddate, 4);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM