我有一张桌子,里面有一些来自能量计的值。一台小型计算机通过RS485读取一些寄存器并将值保存到mysql数据库。那部分工作正常。现在我正在开发一个PHP网站,它以图形方式显示记录的数据。我可以选择一个范围,然后我只会从所选范围中获取值。该网站永远不会超过1000个值。因此,我使用this question来获取仅选择每个第n行的代码(n将根据有多少值计算)。
我已将我的sql commant放到this SQL-Fiddle。我知道我不能在那里工作因为我有一些参数(?)。我只是想向你展示我的环境。
现在我的问题:如何让我当前的查询正常工作/什么错误?它有一个JOIN,因为值必须乘以另一个表中的因子。< / p>
DeviceID和Register将由PHP(mysqli)填写。
答案 0 :(得分:1)
你的SQL很奇怪。
您似乎有很多不使用的用户变量(@STDDATE和@ENDDATE)。您似乎也在使用@REGISTER和@DEVICEID用户变量,以避免必须为这些变量传递两次。
此外,您在几个子查询中初始化这些,但是对每个子查询使用相同的别名。
编辑 - 继续我的评论。
以下似乎可以做您想要的,但尚未经过严格测试。它只使用2个参数。
SELECT *
FROM
(
SELECT
realvalues.`Value` * register.Factor,
realvalues.`Timestamp`,
@X := @X + 1 AS rank,
Sub1.JumpSize
FROM realvalues
JOIN register
ON register.DeviceID = realvalues.DeviceID
JOIN
(
SELECT DeviceID, Register, (1000 / COUNT(*)) AS JumpSize
FROM realvalues
WHERE realvalues.DeviceID = ?
AND realvalues.Register = ?
GROUP BY DeviceID, Register
) Sub1
ON Sub1.DeviceID = realvalues.DeviceID AND Sub1.Register = realvalues.Register
CROSS JOIN (SELECT @X := 0) t
) a
WHERE rank MOD GREATEST(JumpSize, 1) = 0
修改
在这里,您可以找到一个可能的解决方案。
SELECT *
FROM
(
SELECT Register,
`Timestamp`,
Readout,
MOD(NumRecs , rank)
FROM
(
SELECT
realvalues.Register,
realvalues.`Timestamp`,
realvalues.`Value` * register.Factor AS Readout,
@X := @X + 1 AS rank,
Sub1.NumRecs
FROM realvalues
JOIN register
ON register.DeviceID = realvalues.DeviceID
AND register.Register = realvalues.Register
JOIN
(
SELECT DeviceID, Register, COUNT(*) AS NumRecs
FROM realvalues
WHERE realvalues.DeviceID = ?
AND realvalues.Register = ?
GROUP BY DeviceID, Register
) Sub1
ON Sub1.DeviceID = realvalues.DeviceID AND Sub1.Register = realvalues.Register
CROSS JOIN (SELECT @X := 0) t
ORDER BY realvalues.`Timestamp`
) a
ORDER BY MOD(NumRecs , rank)
LIMIT 1000
) b
ORDER BY `Timestamp`
这是获取按时间戳排序的寄存器/设备的所有详细信息以获得排名。然后按照记录总数除以等级的mod对其进行排序,其中包含所需记录数量的LIMIT。这样做的想法是,它得到的总记录除以等级的记录最接近整数,希望均匀分布。然后,结果按时间戳排序。
不确定它会如此高效!
更多的是以一种非常不同的方式做事: -
SELECT register.Register,
DateRanges.RangeStart,
IFNULL(AVG(realvalues.`Value` * register.Factor), 0)
FROM
(
SELECT 1374473600 + (((1374483600 - 1374473600) / 1000) * (units.i + tens.i * 10 + hundreds.i * 100)) AS RangeStart,
1374473600 + (((1374483600 - 1374473600) / 1000) * ( 1 + units.i + tens.i * 10 + hundreds.i * 100)) - 1 AS RangeEnd
FROM (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) hundreds
) DateRanges
LEFT OUTER JOIN realvalues
ON UNIX_TIMESTAMP(realvalues.`Timestamp`) BETWEEN DateRanges.RangeStart AND DateRanges.RangeEnd AND realvalues.DeviceID = 1 AND realvalues.Register = 40001
LEFT OUTER JOIN register
ON register.DeviceID = realvalues.DeviceID AND register.Register = realvalues.Register
GROUP BY Register, DateRanges.RangeStart
ORDER BY Register, DateRanges.RangeStart
这是做一个子查询,在你传递的最小和最大时间戳之间获得1000个时间戳范围(使用unix时间戳)(这里使用1374473600和1374483600只是为了向你展示一个例子),然后对实际值进行左连接并注册以查找哪个读数进入哪个范围。然后使用AVG获取每个日期范围内的平均读数。