我一直在寻找其他几个SO问题,但我无法从中找出解决方案。首先,描述,然后我从其他线程中缺少。 (抬头:我非常清楚我们数据库的非规范化结构,这是我之前在会议中讨论的内容,但这是我们拥有的和我必须合作的内容。)
背景说明
我们有一台机器可以生产25个位置的产品。这些产品的生产数据记录在一个表格中,其中包括记录每个位置的电流和电压。这仅在机器实际生产产品时记录(即在机器中有产品)。没有产品的时间,没有记录任何东西。
该机器可以在两种不同的生产模式下运行:全面生产和R& D生产。完全生产意味着产品被连续插入,以便每个实例始终都有产品(即机器中始终存在25种产品)。第二种模式,R& D生产,一次只生产一种产品(即一种产品进入机器,逐一经历25个实例,当这一个完成时,第二个产品进入机器)。
澄清:每当产品出现时,每个位置每秒记录一次数据,这意味着当完整生产运行时每秒25个实例。当R& D模式运行时,位置1将连续20秒具有~20个实例,位置2将在接下来的20个连续秒内具有~20个实例,依此类推。
表格结构
Productiondata:
问题
我们想要计算机器的正常运行时间,但我们想要将生产模式和R& D模式的正常运行时间分开,我们希望每周将这些数据分开。
猜测解决方案
由于我们每秒都会记录实例,因此我可以计算表格中DISTINCT时间值实例的数量,以找出生产和R& D模式的总运行时间。为了找到R& D模式,我可以肯定地说,只要有一个只有一个条目的时间实例,我就会以R& D模式运行(生产模式将有25个实例)。
到目前为止的进展
我有以下查询,它总结了所有不同的实例,以找到生产和R& D模式:
SELECT YEARWEEK(time) AS YWeek, COUNT(DISTINCT time) AS Time_Seconds, ROUND(COUNT(DISTINCT time)/3600, 1) AS Time_Hours
FROM Database.productiondata
WHERE YEARWEEK(time) >= YEARWEEK(curdate()) - 21
GROUP BY YWeek;
此查询会查找表中有多少个DISTINCT时间实例,并按周计算数字和组。
问题
上面的查询计算了表中存在的实例数量,但我想只查找UNIQUE实例。基本上,我试图找到像IF计数(时间)= 1的东西,然后计算那个实例,IF计数(时间)> 1然后根本不计算它(DISTINCT仍然计算这个)。
我查看了其他几个SO线程,但几乎都解释了如何使用DISTINCT找到唯一值,这只能完成我正在寻找的一半。我得到的最接近的是this,它使用了HAVING子句。我目前陷入以下困境:
SELECT YEARWEEK(time) as YWeek, COUNT(Distinct time) As Time_Seconds, ROUND(COUNT(Distinct time)/3600, 1) As Time_Hours
FROM
(SELECT * FROM Database.productiondata
WHERE time > '2014-01-01 00:00:00'
GROUP BY time
HAVING count(time) = 1) as temptime
GROUP BY YWeek
ORDER BY YWeek;
这里的问题是我们在嵌套的select子句中有一个GROUP BY时间,这需要永远(今年只有约500万行,所以我可以理解)。我的意思是,从语法上来说,我认为这是正确的,但它需要永远的exectue。甚至EXPLAIN这个时候了。
这就是我的地方。这是正确的方法还是有更聪明的方法/需要更少的查询时间/避免按时间分组?
编辑:作为示例,我们有这个表格(格式化道歉,不知道如何在SO上制作表格格式)
id position time
1 1 1
2 2 1
3 5 1
4 19 1
... ... ...
25 7 1
26 3 2
27 6 2
... ... ...
此表显示正在进行生产运行时的样子。如您所见,在表中记录数据时,没有通用结构可以获得第一个条目;会发生的是每25秒记录25个位置,然后根据PLC为每个位置发送数据的速度将数据添加到表中。下表显示了表在研究模式下运行时的样子。
id position time
245 1 1
246 1 2
247 1 3
... ... ...
269 1 25
270 2 26
271 2 27
... ... ...
由于所有数据都合并到一个表中,我们想知道当COUNT(时间)恰好等于1时有多少个实例,或者我们可以在COUNT(时间)严格更大时查找每个实例比1。
EDIT2:作为对Alan的回复,建议给了我
YWeek Time_Seconds Time_Hours
201352 1 0.0
201352 1 0.0
201352 1 0.0
... ... ...
201352 1 0.0 (1000 row limit)
而我想要的输出是
Yweek Time_Seconds Time_Hours
201352 2146 35.8
201401 5789 96.5
... ... ...
201419 8924 148.7
EDIT3 :到目前为止,我已经收集了尝试和结果here,并在查询上方显示了灰色描述。
答案 0 :(得分:1)
您可以通过取消子选择来获得更好的结果:
SELECT YEARWEEK(time) as YWeek,
COUNT(time) As Time_Seconds,
ROUND(COUNT(time)/3600, 1) As Time_Hours
FROM Database.productiondata
WHERE time > '2014-01-01 00:00:00'
GROUP BY YWeek
HAVING count(time) = 1)
ORDER BY YWeek;
我假设time
上有index
,但如果没有,您可以通过添加一个来提高性能。
<强>更新强>
根据最近添加的样本数据,我不确定您的方法是否正确。 time
列似乎是INT
代表秒,而您将DATETIME
视为具有YEARWEEK
的{{1}}。下面我在SQL中有一个工作示例,它完全按照您的要求time
实际上是DATETIME
列:
DECLARE @table TABLE
(
id INT ,
[position] INT ,
[time] DATETIME
)
INSERT INTO @table
VALUES ( 1, 1, DATEADD(week, -1, GETDATE()) )
INSERT INTO @table
VALUES ( 1, 1, DATEADD(week, -2, GETDATE()) )
INSERT INTO @table
VALUES ( 1, 1, DATEADD(week, -2, GETDATE()) )
INSERT INTO @table
VALUES ( 1, 1, DATEADD(week, -2, GETDATE()) )
INSERT INTO @table
VALUES ( 1, 1, DATEADD(week, -2, GETDATE()) )
INSERT INTO @table
VALUES ( 1, 1, DATEADD(week, -3, GETDATE()) )
INSERT INTO @table
VALUES ( 1, 1, DATEADD(week, -3, GETDATE()) )
SELECT CAST(DATEPART(year, [time]) AS VARCHAR)
+ CAST(DATEPART(week, [time]) AS VARCHAR) AS YWeek ,
COUNT([time]) AS Time_Seconds ,
ROUND(COUNT([time]) / 3600, 1) AS Time_Hours
FROM @table
WHERE [time] > '2014-01-01 00:00:00'
GROUP BY DATEPART(year, [time]) ,
DATEPART(week, [time])
HAVING COUNT([time]) > 0
ORDER BY YWeek;
答案 1 :(得分:1)
SELECT pd1.*
FROM Database.productiondata pd1
LEFT JOIN Database.productiondata pd2 ON pd1.time=pd2.time AND pd1.id<pd2.id
WHERE pd1.time > '2014-01-01 00:00:00' AND pd2.time > '2014-01-01 00:00:00'
AND pd2.id IS NULL
您可以LEFT JOIN
到同一张桌子,只留下没有相关的行
更新查询使用SQL小提琴
SELECT pd1.* From productiondata pd1
left Join productiondata pd2
ON pd1.time = pd2.time and pd1.id < pd2.id
Where pd1.time > '2014-01-01 00:00:00' and pd2.id IS NULL;