使用子查询的非常复杂的查询不起作用

时间:2013-07-23 13:55:30

标签: mysql mysqli sqlfiddle

我有一张桌子,里面有一些来自能量计的值。一台小型计算机通过RS485读取一些寄存器并将值保存到mysql数据库。那部分工作正常。现在我正在开发一个PHP网站,它以图形方式显示记录的数据。我可以选择一个范围,然后我只会从所选范围中获取值。该网站永远不会超过1000个值。因此,我使用this question来获取仅选择每个第n行的代码(n将根据有多少值计算)。

我已将我的sql commant放到this SQL-Fiddle。我知道我不能在那里工作因为我有一些参数(?)。我只是想向你展示我的环境。

现在我的问题:如何让我当前的查询正常工作/什么错误?它有一个JOIN,因为值必须乘以另一个表中的因子。< / p>

DeviceID和Register将由PHP(mysqli)填写。

1 个答案:

答案 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获取每个日期范围内的平均读数。