簡體   English   中英

通過分組跨多個表聚合 SQL 查詢

[英]Aggregate SQL query across multiple tables by grouping

我想對來自多個表的記錄進行分組。

樣本數據:

create table UserTable (
  Id integer not null,
  Name varchar(12) not null
);

insert into UserTable  values (1,  'A B');
insert into UserTable  values (2,  'A C');
insert into UserTable  values (3,  'A C A C');
insert into UserTable  values (4,  'A C C');
insert into UserTable  values (5,  'A C B');
insert into UserTable  values (6,  'A C C');
insert into UserTable  values (7,  'A C D');
insert into UserTable  values (8,  'A C E');
insert into UserTable  values (9,  'A C F');


create table LogTable (
  LogId integer not null,
  Username varchar(12) not null,
  Event varchar(12) not null
);

insert into LogTable  values (1, 'A C A C', 'Read');
insert into LogTable  values (2, 'A C F', 'Write');
insert into LogTable  values (3, 'A C F', 'Read');
insert into LogTable  values (4, 'A C C', 'Update');
insert into LogTable  values (5,'A C C', 'Read');
insert into LogTable  values (6,'A C F', 'Read');
insert into LogTable  values (7,'A C F', 'Update');
insert into LogTable  values (7,'A C F', 'Write');
insert into LogTable  values (7,'A C E','Update');
insert into LogTable  values (7,'A C F', 'Delete');
insert into LogTable  values (10,'A C B', 'Delete');
insert into LogTable  values (11, 'A C F','Copy');
insert into LogTable  values (12, 'A C B','Read');
insert into LogTable  values (13, 'A C F','Update');
insert into LogTable  values (14, 'A C F','Copy');
insert into LogTable  values (15, 'A C F','Read');
insert into LogTable  values (16, 'A C F','Update');
insert into LogTable  values (17, 'A C F','Copy');
insert into LogTable  values (18, 'A C C','Read');
insert into LogTable  values (19, 'A C D','Update');

create table Activity (
  Id integer not null,
  ActivityType varchar(12) not null,
  UserId varchar(12) not null
);

insert into Activity  values (1, 'Videos', 8);
insert into Activity  values (2, 'Text',   7);
insert into Activity  values (3, 'Page',   7);
insert into Activity  values (4, 'Text',   7);
insert into Activity  values (5, 'Text',   9);
insert into Activity  values (6, 'Chat',   8);
insert into Activity  values (7, 'Chat',   5);
insert into Activity  values (7, 'File',   8);
insert into Activity  values (7, 'Videos', 1);
insert into Activity  values (7, 'Text',   4);
insert into Activity  values (10, 'Image', 4);
insert into Activity  values (11, 'Image', 6);
insert into Activity  values (12, 'Chat',  3);
insert into Activity  values (13, 'Chat',  2);
insert into Activity  values (14, 'Page',  1);
insert into Activity  values (15, 'Vidoes',1);
insert into Activity  values (16, 'Vidoes',6);
insert into Activity  values (17, 'Vidoes',5);
insert into Activity  values (18, 'Vidoes',5);
insert into Activity  values (19, 'Chat',  5);

我試過的:

SELECT UT.Id,UT.Name,
SUM(CASE 
WHEN LT.Event = 'Read'  THEN 1 
ELSE 0 END
)  AS [USER READ],
SUM(CASE 
WHEN LT.Event = 'Delete'    THEN 1 
ELSE 0 END
)  AS [USER DELETE],
SUM(CASE 
WHEN AC.ActivityType = 'Videos' THEN 1 
WHEN AC.ActivityType = 'Text'   THEN 1  
WHEN AC.ActivityType = 'Page'   THEN 1  
WHEN AC.ActivityType = 'Image'  THEN 1 
ELSE 0 END
)  AS [LEARNING ACTIVITY],
SUM(CASE WHEN AC.ActivityType = 'Chat' THEN 1 ELSE 0 END)  AS [Chat]
FROM UserTable UT
LEFT JOIN Activity AC ON UT.Id = AC.UserId
LEFT JOIN LogTable LT ON LT.Username = UT.Name
GROUP BY UT.Id, UT.Name
        

所需的 Output:

Id  |   Name    |   LEARNING ACTIVITY | Chat  | USER READ | USER DELETE|
------------------------------------------------------------------------
1   |   A B     |   2                 | 0     |     0     |     0      |
2   |   A C     |   0                 | 1     |     0     |     0      |
3   |   A C A C |   0                 | 1     |     1     |     0      |
4   |   A C C   |   2                 | 0     |     2     |     0      |
5   |   A C B   |   0                 | 2     |     1     |     1      |
6   |   A C R   |   1                 | 0     |     0     |     0      |
7   |   A C D   |   3                 | 0     |     0     |     0      |
8   |   A C E   |   1                 | 1     |     0     |     0      |
9   |   A C F   |   1                 | 0     |     3     |     1      |

如何使用IdName聚合兩個不相關和分組的表?

  1. 用戶一起加入和聚合活動
  • 學習活動是(視頻、文本、頁面和圖像)作為ActivityType的總和
  • Chat 是所有以 Chat 作為ActivityType的行
  1. 用戶加入和聚合LogTable

您應該在加入之前進行聚合,這樣可以避免導致多對多的加入導致過度計數:

SELECT UT.Id,UT.Name, 
  coalesce([LEARNING ACTIVITY],0),
  coalesce([Chat],0),
  coalesce([USER READ],0),
  coalesce([USER DELETE],0)
FROM UserTable UT
LEFT JOIN 
 (
   select UserId, 
      SUM(CASE 
            WHEN ActivityType = 'Videos' THEN 1 
            WHEN ActivityType = 'Text'   THEN 1  
            WHEN ActivityType = 'Page'   THEN 1  
            WHEN ActivityType = 'Image'  THEN 1 
            ELSE 0
          END)  AS [LEARNING ACTIVITY],
       SUM(CASE WHEN ActivityType = 'Chat' THEN 1 ELSE 0 END)  AS [Chat]
   from Activity
   group by UserId
 ) AC
ON UT.Id = AC.UserId
LEFT JOIN 
 (
   select Username, 
      SUM(CASE 
            WHEN Event = 'Read'  THEN 1 
            ELSE 0 END
         )  AS [USER READ],
      SUM(CASE 
            WHEN Event = 'Delete'    THEN 1 
            ELSE 0 END
         )  AS [USER DELETE]
   from LogTable
   group by UserName
  ) LT
ON LT.Username = UT.Name

小提琴

簡化 CASE(COALESCE 處理 NULL):

SELECT UT.Id,UT.Name, 
  coalesce([LEARNING ACTIVITY],0),
  coalesce([Chat],0),
  coalesce([USER READ],0),
  coalesce([USER DELETE],0)
FROM UserTable UT
LEFT JOIN 
 (
   select UserId, 
      SUM(CASE WHEN ActivityType IN ('Videos','Text','Page','Image') THEN 1 END)  AS [LEARNING ACTIVITY],
      SUM(CASE WHEN ActivityType = 'Chat' THEN 1 END)  AS [Chat]
   from Activity
   group by UserId
 ) AC
ON UT.Id = AC.UserId
LEFT JOIN 
 (
   select Username, 
      SUM(CASE WHEN Event = 'Read'   THEN 1 END)  AS [USER READ],
      SUM(CASE WHEN Event = 'Delete' THEN 1 END)  AS [USER DELETE]
   from LogTable
   group by UserName
  ) LT
ON LT.Username = UT.Name

我建議您使用窗口函數和外部應用來執行您需要的聚合。 這是我提出的與您的預期結果相匹配的查詢:

https://docs.microsoft.com/en-us/sql/t-sql/queries/select-over-clause-transact-sql?view=sql-server-ver15

https://docs.microsoft.com/en-us/u-sql/statements-and-expressions/select/from/select-selecting-from-cross-apply-and-outer-apply

select distinct
    UserId,
    UT.Name,
    sum(case when A.ActivityType in ('Videos','Text','Page','Image') then 1 else 0 end) over (partition by UserId) [Learning Activity],
    sum(case when A.ActivityType = 'Chat' then 1 else 0 end) over (partition by UserId) Chat,
    coalesce(LT2.[User Read],0) as [User Read],
    coalesce(LT2.[User Delete],0) as [User Delete]
from Activity A
join UserTable UT
    on A.UserId = UT.Id
outer apply
(
    select distinct
        sum(case when LT.[Event] = 'Read' then 1 else 0 end) over (partition by UserId) [User Read],
        sum(case when LT.[Event] = 'Delete' then 1 else 0 end) over (partition by UserId) [User Delete]
    from LogTable LT
    where LT.Username = UT.Name

) LT2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM