如何编写查询来清理给定问题的表
Posted
技术标签:
【中文标题】如何编写查询来清理给定问题的表【英文标题】:How to write a query to clean up table for given problem 【发布时间】:2020-06-07 08:31:53 【问题描述】:我有一些数据库,我需要从一个表中清理一些数据,我想相当自动地这样做。
首先是架构:这个数据库中有几个表,但我只需要专门清理一个表。
表名是CollectedProducts
:
[Id] [int] IDENTITY(1,1) NOT NULL,
[Date] [date] NOT NULL,
[Time] [time](7) NOT NULL,
[BouquetId] [int] NOT NULL,
[EmployeeId] [int] NOT NULL,
[ProductionEnd] [bit] NOT NULL
我对最后一列感兴趣,ProductionEnd
,它指出特定员工是否在特定日期完成了生产。
此列的逻辑约束是,在给定日期的生产结束时,必须至少有一行将此列设置为 1。所以它基本上是员工在某一天的最后一行。
一天中还可以有其他行设置为 1,表示员工有更长的休息时间。
其后不得有另一行,其值设置为 1。
现在考虑到这些限制,我想选择具有无效 ProductionEnd
值的所有行,这样这不是每个(天,员工)对的最后一行,我还想保留所有带有 @ 的行987654325@ 设置为 1,这不是最后一行,但也没有后跟 / 前面有另一行,根据我上面描述的约束,此列设置为 1。
这样的查询怎么写?
【问题讨论】:
您没有给出完整的架构,因为没有表名。另外,您尝试自己编写此查询是什么? 我正在尝试选择最后一行,但我不确定如何保留那些不在最后一行的孤 1 的“岛屿”。 @kamilwydrzycki 。 . .样本数据和期望的结果会有所帮助。 【参考方案1】:您可以使用窗口函数来做到这一点。基本上,对于每一天,您都希望有 ProductionEnd = 1
的行,并且其他行存在于稍后的时间和 ProductionEnd = 1
并且没有行存在于稍后的时间和 ProductionEnd = 0
。
你可以这样表述:
select *
from (
select
cp.*,
sum(ProductionEnd)
over(partition by EmployeeId, Date order by Time desc) nbProdEnd,
sum(case when ProductionEnd = 1 then 0 else 1 end)
over(partition by EmployeeId, Date order by Time desc) nbNonProdEnd
from CollectedProducts cp
) t
where nbProdEnd > 1 and nbNonProdEnd = 0
【讨论】:
【参考方案2】:如果您只想要最后一行不是“1”的日期/员工对,那么您可以使用first_value()
。以下获取员工日期的所有行:
select cp.*
from (select cp.*,
first_value(productionEnd) over (partition by EmployeeId, Date order by Time desc) as last_productionEnd
from CollectedProducts cp
) cp
where last_productionEnd <> 1;
如果你只想要最后一个,你可以使用:
select cp.*
from (select cp.*,
row_number() over (partition by EmployeeId, Date order by Time desc) as seqnum
from CollectedProducts cp
) cp
where seqnum = 1 and last_productionEnd <> 1;
【讨论】:
以上是关于如何编写查询来清理给定问题的表的主要内容,如果未能解决你的问题,请参考以下文章