sql-server - 将缺失记录添加到结果表记录中

标签 sql-server t-sql

我遇到以下问题:我有两个表

Article
id     state
Guid    int

Article_history
id   state   datechange
Guid  int     datetime

第一个表存储产品信息,第二个表填充,然后产品状态发生更改。例如

Article
id     state
1       1

Article_history
id   state   datechange
1     1      2019-11-10
1     2      2020-01-15

我需要为几年内的每一篇文章创建一份报告,步长为一个月:

date         id   state
2019-11-01   1    1
2019-12-01   1    1 --There is my problem
2020-01-01   1    2

我创建了对Article_history表的查询,但由于我的应用程序仅在更改文章状态时创建记录,因此并非每个月都会在Article_history中显示。在我的示例中,我实际上没有 2019-12-01 的记录。我需要用最后已知的状态来填补每个产品的时间间隙。

我无法想象在给定期间的每个月不使用光标的情况下填补这一空白的方法,但这需要很多时间。 请给我建议。

模拟

 Create TABLE Article
(
    id int,
    state int
)

Create TABLE Article_history
(
    id int,
    datechange datetime,
    state int
)

Insert into Article (id, state)
VALUES (1,1)
,(2,1)
,(3,2)

INSERT into Article_history (id, datechange, state)
VALUES (1,'2019-11-10',1)
,(1,'2020-01-15',2);

我的查询:

 With theDates As
(
    Select DATEFROMPARTS(2019,11,1) as theDate
    Union All
    Select DateAdd(MONTH,1,theDate)
    From theDates
    Where DATEADD(MONTH,1,theDate)<=GETDATE()
)
Select 
    Convert(date,dt.theDate,104) as 'date'
    ,arth.id
    ,arth.state
From theDates as dt
left join Article_history as arth
on arth.datechange>=DATEADD(month, DATEDIFF(month, 0, dt.theDate), 0) and arth.datechange<=EOMONTH(dt.theDate)
Option (Maxrecursion 0)

我的结果:

date         id   state
2019-11-01   1    1
2020-01-01   1    2

我想要得到

 date         id   state
 2019-11-01   1    1
 2019-12-01   1    1 
 2020-01-01   1    2

十二月不见了

为了澄清我的问题:来自 Article 的记录可能根本不在 Article_history 中,如果是这样,我想将此记录放入每个月并带有一些默认值。

UPD:Article 表有大约 3k 条记录。 Article 中的 PR id 是 Article_history 的 FK。我需要为 Article 中的每条记录创建一个表示。在伪代码中:

foreach article in Article {
  foreach month in TheDates {
    if(article.id not in result where result.month = month) {
      AddInResult(new [result.month=month, result.id=article.id, result.state = GetLastStateFromArticleHistory(article.id,month)]
    }
 }}

我有一个包含历史记录的结果表,但并未代表每个月的所有文章。我需要添加此记录以及来自 Article_history 的最后可用状态。

最佳答案

首先,在提供最小示例和创建脚本方面做得很好。 另外,已经构建了所需的计数表,这很好——有很多方法,cte 就可以了。

现在,你的结果与我的不匹配。我得到了第三列,其中 id 和状态为 12 月的 NULL。也许您实际上运行了内部联接?

With theDates As
(
    Select DATEFROMPARTS(2019,11,1) as theDate
    Union All
    Select DateAdd(MONTH,1,theDate)
    From theDates
    Where DATEADD(MONTH,1,theDate)<=GETDATE()
)
Select 
    Convert(date,dt.theDate,104) as 'date'
    ,a.id
    ,lastone.*
From theDates as dt
cross join Article a -- cartesian product of dates * articles
outer apply
(
    select top 1 state
    from Article_history as arth
    where 
        arth.datechange<EOMONTH(dt.theDate)
        and a.id=arth.id
    order by arth.datechange desc
) as lastone
order by id,dt.theDate

Result:

+------------+----+-------+
|    date    | id | state |
+------------+----+-------+
| 2019-11-01 |  1 | 1     |
| 2019-12-01 |  1 | 1     |
| 2020-01-01 |  1 | 2     |
| 2019-11-01 |  2 | NULL  |
| 2019-12-01 |  2 | NULL  |
| 2020-01-01 |  2 | NULL  |
| 2019-11-01 |  3 | NULL  |
| 2019-12-01 |  3 | NULL  |
| 2020-01-01 |  3 | NULL  |
+------------+----+-------+

关于sql-server - 将缺失记录添加到结果表记录中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59985681/

相关文章:

sql-server - 用于 SQL Server 的 MySQL Workbench?

sql - 解决连续性的日期范围(GAPS AND ISLANDS)

sql - T SQL 累积减法

sql-server - 我们可以使用 Group by 子句执行像删除这样的 DML 操作吗?

sql-server-2008 - 无效的对象名称 - SQL Server 2008

sql - 无法启动本地数据库

sql-server - 是否可以回滚 SQL Server 事务而不抑制错误?

sql - 每个不同ID的累计总和

sql - 在 SQL Server 2000 中强制对 OR 使用 UNION 进行优化

sql-server - 用于查找 UDF 上次执行时间的 SQL 查询