2013-07-23 46 views
-5

我有一張表,其中包含一些來自電錶的值。一臺小型計算機通過RS485讀取一些寄存器並將值保存到mysql數據庫。這部分工作正常。現在我正在開發一個PHP網站,它在圖表中顯示記錄的數據。我可以選擇一個範圍,然後我只會從選定範圍內獲取值。該網站應該永遠不會超過1000個值。正因爲如此,我用this question得到一個代碼,只選擇每一個第n行(n將計算有多少值)。帶有子查詢的非常複雜的查詢不起作用

我已經把我的sql commant到this SQL-Fiddle。我知道我不能在那裏工作,因爲我在那裏有一些參數(?)。我只是想向你展示我的環境。

現在我的問題:我怎樣才能得到我當前的查詢工作/它有什麼不對?它有一個JOIN,因爲值必須乘以另一個表中的因子。

DeviceID和Register將被PHP(mysqli)填入。

+0

對不起,但「幫我處理我的複雜查詢」問題在這裏被視爲「太本地化以至於無法被允許」。只有一種方法可以使某些工作 - 調試它。 –

+0

順便說一句,選擇一個壞的數據庫設計的每一個第n行的氣味。數據庫中沒有順序,根本沒有第n行。 –

+0

我已經嘗試刪除部件。 –

回答

1

你的SQL很奇怪。

您似乎有很多不使用的用戶變量(@STARTDATE和@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對排序進行排序,並以您想要的記錄數限制。這樣做的想法是,它得到的總排名除以排名的記錄最接近整數,希望均勻分佈。然後,這些結果按時間戳排序。

不知道它會那樣高效!

有更多的發揮,與做事情的方式非常不同: -

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獲取每個日期範圍內的平均讀數。

+0

我應該放一些嗎?並設置一些變量兩次? –

+0

這可能會更容易,或者可能更容易做一個簡單的子查詢將這些參數傳遞給它,然後根據它進行連接。會添加一個例子。 – Kickstart

+0

我獲得30次相同的註冊! http://sqlfiddle.com/#!2/6dc97/57 –