SQL聚合查询-计数为空

SQL聚合查询-计数为空,sql,tsql,join,count,aggregate-functions,Sql,Tsql,Join,Count,Aggregate Functions,我有一个数据库,我们有一个工作列表。每个作业位于1到多个位置。用户可以在任何位置申请工作。他们可以在不同的地点分别申请同一份工作。每个职务申请从1开始有4种状态。新到4。关闭 我需要运行一个SQL查询来显示每个作业、每个位置的摘要,以及每个状态的相关应用程序计数。比如说 + ---- + -------- + ------ + ----- + | Job | Location | Status | Count | + ---- + -------- + ------ + ----- + | 1

我有一个数据库,我们有一个工作列表。每个作业位于1到多个位置。用户可以在任何位置申请工作。他们可以在不同的地点分别申请同一份工作。每个职务申请从1开始有4种状态。新到4。关闭

我需要运行一个SQL查询来显示每个作业、每个位置的摘要,以及每个状态的相关应用程序计数。比如说

+ ---- + -------- + ------ + ----- +
| Job  | Location | Status | Count |
+ ---- + -------- + ------ + ----- +
| 1000 | 1        | 1      | 7     |
| 1000 | 1        | 2      | 0     |
| 1000 | 1        | 3      | 1     |
| 1000 | 1        | 4      | 1     |
| 1000 | 2        | 1      | 4     |
| 1000 | 2        | 2      | 2     |
| 1000 | 2        | 3      | 0     |
| 1000 | 2        | 4      | 8     |
+ ---- + -------- + ------ + ----- +
此外,我理想地希望将4个状态计数相加,形成同一列表中的总和

这是我到目前为止编写的SQL语句:-

SELECT B.JobID, B.LocationID, B.ApplicationStatusID, COUNT(B.JobID) AS CountOfResults
FROM Job AS A
JOIN JobApplication AS B ON A.JobID = B.JobID
LEFT JOIN JobApplicationStatus AS C ON B.ApplicationStatusID = C.JobApplicationStatusID
WHERE A.BrandID = 1
GROUP BY B.JobID, B.LocationID, B.ApplicationStatusID
它是有效的,除了两件事:-

  • 我不确定如何获取总计数(或者我可以稍后在服务器端执行此操作)
  • 当计数为0时,它不会显示结果
有谁能建议如何在每个位置为每个工作获得4个状态,即使是0?我已经看到关于左连接的其他线程的各种建议,但我还没有成功

提前谢谢

编辑-显示作业表示例数据

假设工作地点是ID号为5、6和7的地址表

Job
+ ------ + ---------- + ------------------- +
| Job ID | Job Title  | Description         |
+ ------ + ---------- + ------------------- +
| 1      | Developer  | My Nice Description |
| 2      | Full Stack | Another Description |
+ ------ + ---------- + ------------------- +

Job Location
+ -- + ------ + ----------- +
| ID | Job ID | Location ID |
+ -- + ------ + ----------- +
| 1  | 1      | 5           |
| 2  | 1      | 6           |
| 3  | 2      | 5           |
| 4  | 2      | 6           |
| 5  | 2      | 7           |
+ -- + ------ + ----------- +

Job Application
+ -- + ------- + ------ + ----------- + --------------------- +
| ID | User ID | Job ID | Location ID | Application Status ID |
+ -- + ------- + ------ + ----------- + --------------------- +
| 1  | 1       | 1      | 5           | 1                     |
| 2  | 1       | 1      | 6           | 2                     |
| 3  | 2       | 1      | 5           | 1                     |
| 4  | 2       | 2      | 7           | 4                     |
+ -- + ------- + ------ + ----------- + --------------------- +
在“职务申请状态”表中:-

  • 用户1在位置5申请作业1,其申请状态为1

  • 用户1也在位置6申请作业1,其申请状态为2

  • 用户2在位置5申请作业1,其申请状态为1

  • 用户2也在位置7申请作业2,其申请状态为4

我在这里寻找的是返回以下内容的查询:-

Result
+ --- + -------- + ------ + ----- +
| Job | Location | Status | Count |
+ --- + -------- + ------ + ----- +
| 1   | 5        | 1      | 2     |
| 1   | 5        | 2      | 0     |
| 1   | 5        | 3      | 0     |
| 1   | 5        | 4      | 0     |
| 1   | 6        | 1      | 0     |
| 1   | 6        | 2      | 1     |
| 1   | 6        | 3      | 0     |
| 1   | 6        | 4      | 0     |
+ --- + -------- + ------ + ----- +

以此类推,应显示0。计数是处于该状态编号的工作申请的计数。有4个状态号,它们在一个名为JobApplicationStatus的联接表中设置。

您就快到了。因为即使在求职申请中没有对应关系,您也需要所有状态,所以您需要使用

此外,在这种情况下,因为每个状态都有一个“链接”,所以您需要在案例场景中使用SUM而不是COUNT

MS SQL Server 2014架构设置

CREATE TABLE Job
    ([JobID] int, [JobTitle] varchar(10), [Description] varchar(23), [BrandID] int)
;

INSERT INTO Job
    ([JobID], [JobTitle], [Description], [BrandID])
VALUES
    (1, 'Developer', 'My nice description', 1),
    (2, 'Full Stack', 'Another job description', 1)
;


CREATE TABLE JobApplication
    ([ID] int, [UserID] int, [JobID] int, [LocationID] int, [ApplicationStatusID] int)
;

INSERT INTO JobApplication
    ([ID], [UserID], [JobID], [LocationID], [ApplicationStatusID])
VALUES
    (1, 1, 1, 5, 1),
    (2, 1, 1, 6, 2),
    (3, 2, 1, 5, 1),
    (4, 2, 2, 7, 4)
;


CREATE TABLE JobApplicationStatus
    ([JobApplicationStatusID] int, [Description] varchar(11))
;

INSERT INTO JobApplicationStatus
    ([JobApplicationStatusID], [Description])
VALUES
    (1, 'New'),
    (2, 'In Progress'),
    (3, 'Hold'),
    (4, 'Closed')
;
SELECT B.JobID, B.LocationID, C.JobApplicationStatusID, 
sum(case when B.ApplicationStatusID = C.JobApplicationStatusID then 1 else 0 end) AS CountOfResults
FROM Job AS A
JOIN JobApplication AS B ON A.JobID = B.JobID
cross join JobApplicationStatus AS C
WHERE A.BrandID = 1
GROUP BY B.JobID, B.LocationID, C.JobApplicationStatusID
| JobID | LocationID | JobApplicationStatusID | CountOfResults |
|-------|------------|------------------------|----------------|
|     1 |          5 |                      1 |              2 |
|     1 |          5 |                      2 |              0 |
|     1 |          5 |                      3 |              0 |
|     1 |          5 |                      4 |              0 |
|     1 |          6 |                      1 |              0 |
|     1 |          6 |                      2 |              1 |
|     1 |          6 |                      3 |              0 |
|     1 |          6 |                      4 |              0 |
|     2 |          7 |                      1 |              0 |
|     2 |          7 |                      2 |              0 |
|     2 |          7 |                      3 |              0 |
|     2 |          7 |                      4 |              1 |
查询1

CREATE TABLE Job
    ([JobID] int, [JobTitle] varchar(10), [Description] varchar(23), [BrandID] int)
;

INSERT INTO Job
    ([JobID], [JobTitle], [Description], [BrandID])
VALUES
    (1, 'Developer', 'My nice description', 1),
    (2, 'Full Stack', 'Another job description', 1)
;


CREATE TABLE JobApplication
    ([ID] int, [UserID] int, [JobID] int, [LocationID] int, [ApplicationStatusID] int)
;

INSERT INTO JobApplication
    ([ID], [UserID], [JobID], [LocationID], [ApplicationStatusID])
VALUES
    (1, 1, 1, 5, 1),
    (2, 1, 1, 6, 2),
    (3, 2, 1, 5, 1),
    (4, 2, 2, 7, 4)
;


CREATE TABLE JobApplicationStatus
    ([JobApplicationStatusID] int, [Description] varchar(11))
;

INSERT INTO JobApplicationStatus
    ([JobApplicationStatusID], [Description])
VALUES
    (1, 'New'),
    (2, 'In Progress'),
    (3, 'Hold'),
    (4, 'Closed')
;
SELECT B.JobID, B.LocationID, C.JobApplicationStatusID, 
sum(case when B.ApplicationStatusID = C.JobApplicationStatusID then 1 else 0 end) AS CountOfResults
FROM Job AS A
JOIN JobApplication AS B ON A.JobID = B.JobID
cross join JobApplicationStatus AS C
WHERE A.BrandID = 1
GROUP BY B.JobID, B.LocationID, C.JobApplicationStatusID
| JobID | LocationID | JobApplicationStatusID | CountOfResults |
|-------|------------|------------------------|----------------|
|     1 |          5 |                      1 |              2 |
|     1 |          5 |                      2 |              0 |
|     1 |          5 |                      3 |              0 |
|     1 |          5 |                      4 |              0 |
|     1 |          6 |                      1 |              0 |
|     1 |          6 |                      2 |              1 |
|     1 |          6 |                      3 |              0 |
|     1 |          6 |                      4 |              0 |
|     2 |          7 |                      1 |              0 |
|     2 |          7 |                      2 |              0 |
|     2 |          7 |                      3 |              0 |
|     2 |          7 |                      4 |              1 |

CREATE TABLE Job
    ([JobID] int, [JobTitle] varchar(10), [Description] varchar(23), [BrandID] int)
;

INSERT INTO Job
    ([JobID], [JobTitle], [Description], [BrandID])
VALUES
    (1, 'Developer', 'My nice description', 1),
    (2, 'Full Stack', 'Another job description', 1)
;


CREATE TABLE JobApplication
    ([ID] int, [UserID] int, [JobID] int, [LocationID] int, [ApplicationStatusID] int)
;

INSERT INTO JobApplication
    ([ID], [UserID], [JobID], [LocationID], [ApplicationStatusID])
VALUES
    (1, 1, 1, 5, 1),
    (2, 1, 1, 6, 2),
    (3, 2, 1, 5, 1),
    (4, 2, 2, 7, 4)
;


CREATE TABLE JobApplicationStatus
    ([JobApplicationStatusID] int, [Description] varchar(11))
;

INSERT INTO JobApplicationStatus
    ([JobApplicationStatusID], [Description])
VALUES
    (1, 'New'),
    (2, 'In Progress'),
    (3, 'Hold'),
    (4, 'Closed')
;
SELECT B.JobID, B.LocationID, C.JobApplicationStatusID, 
sum(case when B.ApplicationStatusID = C.JobApplicationStatusID then 1 else 0 end) AS CountOfResults
FROM Job AS A
JOIN JobApplication AS B ON A.JobID = B.JobID
cross join JobApplicationStatus AS C
WHERE A.BrandID = 1
GROUP BY B.JobID, B.LocationID, C.JobApplicationStatusID
| JobID | LocationID | JobApplicationStatusID | CountOfResults |
|-------|------------|------------------------|----------------|
|     1 |          5 |                      1 |              2 |
|     1 |          5 |                      2 |              0 |
|     1 |          5 |                      3 |              0 |
|     1 |          5 |                      4 |              0 |
|     1 |          6 |                      1 |              0 |
|     1 |          6 |                      2 |              1 |
|     1 |          6 |                      3 |              0 |
|     1 |          6 |                      4 |              0 |
|     2 |          7 |                      1 |              0 |
|     2 |          7 |                      2 |              0 |
|     2 |          7 |                      3 |              0 |
|     2 |          7 |                      4 |              1 |
编辑:

DECLARE @Job TABLE(
        JobId tinyint,
        JobTitle varchar(55),
        JobDescription varchar(55)
);

INSERT INTO @Job 
    VALUES 
    (1,'Developer','My nice description'), 
    (2,'Full Stack','Another job description');

DECLARE @JobLocation TABLE(
    Id tinyint,
    JobId tinyint,
    LocationId tinyint

);

INSERT INTO @JobLocation 
    VALUES 
    (1,1,5), 
    (2,1,6),
    (3,2,5),
    (4,2,6),
    (5,2,7);

DECLARE @JobApplication TABLE(
    Id tinyint,
    UserId tinyint,
    JobId tinyint,
    LocationId tinyint,
    ApplicationStatusId tinyint
);

INSERT INTO @JobApplication
    VALUES
    (1,1,1,5,1),
    (2,1,1,6,2),
    (3,2,1,5,1),
    (4,2,2,7,4);
--End sample data

DECLARE @JobStatus TABLE(
    StatusId int,
    ApplicationStatus varchar(55)
);

INSERT INTO @JobStatus
    VALUES
    (1, 'Application Received'),
    (2, 'Application Review Started'),
    (3, 'Application In Final Review'),
    (4, 'Application Closed');
select job.JobId,
       jl.LocationId,
       js.StatusId,
       count(ja.Id) as StatusCount

from @Job job
    cross apply @JobStatus js 
    inner join @JobLocation jl on job.JobId = jl.JobId
    left join @JobApplication ja on job.JobId = ja.JobId 
        and ja.LocationId = jl.LocationId 
        and ja.ApplicationStatusId = js.StatusId
where job.JobId = 1 -- filter for single job
group by job.jobId, jl.LocationId, js.StatusId
order by job.JobId, jl.LocationId, js.StatusId

有一种方法可以使作业id没有应用程序。只需将
JOIN-JobApplication
更改为
LEFT-OUTER-job-JobApplication
,并在
SELECT
中更改
B.JobID
,以及带有
A.JobID

GROUP BY BY
子句的
GROUP>(
左连接
/
分组依据
)或子查询。这建议:

SELECT j.JobID, l.LocationID, ja.ApplicationStatusID,
       COUNT(ja.JobID) AS CountOfResults
FROM Job j CROSS JOIN
     Location l LEFT JOIN
     JobApplication ja
     ON j.JobID = jb.JobID AND
        l.LocationId = jb.LocationId
WHERE j.BrandID = 1
GROUP BY j.JobID, l.LocationID, ja.ApplicationStatusID

使用count可以在没有案例的情况下获得相同的结果。我提出了与Fabien几乎完全相同的解决方案。交叉连接是这里的关键

设置:

DECLARE @Job TABLE(
        JobId tinyint,
        JobTitle varchar(55),
        JobDescription varchar(55)
);

INSERT INTO @Job 
    VALUES 
    (1,'Developer','My nice description'), 
    (2,'Full Stack','Another job description');

DECLARE @JobLocation TABLE(
    Id tinyint,
    JobId tinyint,
    LocationId tinyint

);

INSERT INTO @JobLocation 
    VALUES 
    (1,1,5), 
    (2,1,6),
    (3,2,5),
    (4,2,6),
    (5,2,7);

DECLARE @JobApplication TABLE(
    Id tinyint,
    UserId tinyint,
    JobId tinyint,
    LocationId tinyint,
    ApplicationStatusId tinyint
);

INSERT INTO @JobApplication
    VALUES
    (1,1,1,5,1),
    (2,1,1,6,2),
    (3,2,1,5,1),
    (4,2,2,7,4);
--End sample data

DECLARE @JobStatus TABLE(
    StatusId int,
    ApplicationStatus varchar(55)
);

INSERT INTO @JobStatus
    VALUES
    (1, 'Application Received'),
    (2, 'Application Review Started'),
    (3, 'Application In Final Review'),
    (4, 'Application Closed');
select job.JobId,
       jl.LocationId,
       js.StatusId,
       count(ja.Id) as StatusCount

from @Job job
    cross apply @JobStatus js 
    inner join @JobLocation jl on job.JobId = jl.JobId
    left join @JobApplication ja on job.JobId = ja.JobId 
        and ja.LocationId = jl.LocationId 
        and ja.ApplicationStatusId = js.StatusId
where job.JobId = 1 -- filter for single job
group by job.jobId, jl.LocationId, js.StatusId
order by job.JobId, jl.LocationId, js.StatusId
查询:

DECLARE @Job TABLE(
        JobId tinyint,
        JobTitle varchar(55),
        JobDescription varchar(55)
);

INSERT INTO @Job 
    VALUES 
    (1,'Developer','My nice description'), 
    (2,'Full Stack','Another job description');

DECLARE @JobLocation TABLE(
    Id tinyint,
    JobId tinyint,
    LocationId tinyint

);

INSERT INTO @JobLocation 
    VALUES 
    (1,1,5), 
    (2,1,6),
    (3,2,5),
    (4,2,6),
    (5,2,7);

DECLARE @JobApplication TABLE(
    Id tinyint,
    UserId tinyint,
    JobId tinyint,
    LocationId tinyint,
    ApplicationStatusId tinyint
);

INSERT INTO @JobApplication
    VALUES
    (1,1,1,5,1),
    (2,1,1,6,2),
    (3,2,1,5,1),
    (4,2,2,7,4);
--End sample data

DECLARE @JobStatus TABLE(
    StatusId int,
    ApplicationStatus varchar(55)
);

INSERT INTO @JobStatus
    VALUES
    (1, 'Application Received'),
    (2, 'Application Review Started'),
    (3, 'Application In Final Review'),
    (4, 'Application Closed');
select job.JobId,
       jl.LocationId,
       js.StatusId,
       count(ja.Id) as StatusCount

from @Job job
    cross apply @JobStatus js 
    inner join @JobLocation jl on job.JobId = jl.JobId
    left join @JobApplication ja on job.JobId = ja.JobId 
        and ja.LocationId = jl.LocationId 
        and ja.ApplicationStatusId = js.StatusId
where job.JobId = 1 -- filter for single job
group by job.jobId, jl.LocationId, js.StatusId
order by job.JobId, jl.LocationId, js.StatusId

Fabien的答案很好,你应该把这个标记为答案,但我只想补充一点,你可以通过使用一个公共表表达式和一个与他的查询相关的子查询得到你想要的总和

; with 
    StatusCounts as (
        SELECT  B.JobID, B.LocationID, C.JobApplicationStatusID, 
                sum(case when B.ApplicationStatusID = C.JobApplicationStatusID then 1 else 0 end) AS CountOfResults
            FROM Job AS A
            JOIN JobApplication AS B ON A.JobID = B.JobID
            cross join JobApplicationStatus AS C
            WHERE A.BrandID = 1
            GROUP BY B.JobID, B.LocationID, C.JobApplicationStatusID
    )
select  *,
        (select SUM(CountOfResults)
            from StatusCounts SQ
            where SQ.JobID = D.JobID
                and SQ.LocationID = D.LocationID
        ) as TotalSum
    from StatusCounts D

您使用的是哪个版本的sql server?还请显示预期的输出。刚刚更新以显示上面的预期输出。sql server 2014。您想在哪里显示总和?这应该是一列吗?您的意思是没有JobApplication的作业没有计数?然后使用外部联接:
从作业作为左联接JobApplication
。a边注意:没有意义的别名只会混淆。请改用有意义的缩写,例如
j
用于
Job
a
ja
用于JobApplication等。