2013-11-03 54 views
1

我使用1-Wire溫度傳感器和名爲「LogTemp」的Windows應用程序記錄溫度值。MySQL使用可變列名創建視圖

此應用程序會自動將溫度值存儲在MySQL數據庫中。

這是溫度日誌數據庫:

mysql> show columns from logtemp; 
+------------------+----------+------+-----+---------------------+-------+ 
| Field | Type | Null | Key | Default | Extra | 
+------------------+----------+------+-----+---------------------+-------+ 
| DATETIME | datetime | NO | PRI | 0000-00-00 00:00:00 | | 
| 0400080224D59710 | float | YES | | NULL | | 
| CA00080224DDD010 | float | YES | | NULL | | 
| 5600080224E7FE10 | float | YES | | NULL | | 
| 0500080224D40B10 | float | YES | | NULL | | 
+------------------+----------+------+-----+---------------------+-------+ 

內容如下所示:

mysql> select * from logtemp limit 10; 
+---------------------+------------------+------------------+------------------+------------------+ 
| DATETIME | 0400080224D59710 | CA00080224DDD010 | 5600080224E7FE10 | 0500080224D40B10 | 
+---------------------+------------------+------------------+------------------+------------------+ 
| 2013-11-01 12:58:01 | 25.75 | 24.19 | 24.31 | 24.44 | 
| 2013-11-01 12:59:03 | 25.81 | 24.19 | 24.31 | 24.44 | 
| 2013-11-01 13:00:05 | 25.94 | 24.25 | 24.38 | 24.44 | 
| 2013-11-01 13:01:07 | 25.94 | 24.25 | 24.38 | 24.44 | 
| 2013-11-01 13:02:08 | 25.94 | 24.31 | 24.38 | 24.5 | 
| 2013-11-01 13:03:10 | 26.06 | 24.31 | 24.38 | 24.5 | 
| 2013-11-01 13:04:11 | 26.19 | 24.31 | 24.44 | 24.56 | 
| 2013-11-01 13:05:13 | 26.31 | 24.31 | 24.44 | 24.56 | 
| 2013-11-01 13:06:14 | 26.38 | 24.31 | 24.44 | 24.56 | 
| 2013-11-01 13:07:16 | 26.38 | 24.31 | 24.44 | 24.56 | 
+---------------------+------------------+------------------+------------------+------------------+ 

的列名(0400080224D59710等)是溫度傳感器的獨特的ID ROM 。當連接一個新傳感器時,數據庫中的附加列正在創建 - 將傳感器的ROM ID作爲列名稱。現在

,我添加另一個表看起來像這樣:

mysql> show columns from sensoren; 
+--------------------------+--------------+------+-----+---------+-------+ 
| Field | Type | Null | Key | Default | Extra | 
+--------------------------+--------------+------+-----+---------+-------+ 
| strSensorHex | varchar(16) | NO | PRI | NULL | | 
| strSensorBeschreibung | varchar(100) | NO | MUL | NULL | | 
| strSensorRRDTabellenName | varchar(25) | NO | | NULL | | 
+--------------------------+--------------+------+-----+---------+-------+ 

該表的內容是:

mysql> select * from sensoren; 
+------------------+-----------------------+--------------------------+ 
| strSensorHex | strSensorBeschreibung | strSensorRRDTabellenName | 
+------------------+-----------------------+--------------------------+ 
| 0400080224D59710 | Testsensor 1 | TEST1 | 
| CA00080224DDD010 | Testsensor 2 | TEST2 | 
| 5600080224E7FE10 | Testsensor 3 | TEST3 | 
| 0500080224D40B10 | Testsensor 4 | TEST4 | 
+------------------+-----------------------+--------------------------+ 

strSensorHex列包含溫度傳感器的獨特的ID ROM。

現在我想創建一個包含以下信息的新觀點:

DATETIME, strSensorHex, strSensorBeschreibung, Temperatur value 

我想已經到谷歌的信息,有關如何實現這一點,但我無法找到一個答案了,我不是很熟悉SQL語法:-(

+4

這是一個糟糕的數據庫設計。變量數據應該存儲在**表中,而不是存儲在列名中。你錯誤的設計是爲什麼你不能創建一個視圖來顯示它。 – Barmar

+0

我同意Barman的評論,但在我看來,似乎並沒有可能改變這個程序在生成表格的行爲方式,至少從它的網站上可以判斷出來。 – Cynical

+0

不幸的是,無法更改數據庫設計。它在LogTemp應用程序中被硬編碼。 – Piet

回答

0

一種可能的解決方案是使用動態SQL和存儲的過程,而不是一個視圖的

DELIMITER $$ 
CREATE PROCEDURE sensortemp() 
BEGIN 
    SET @sql = NULL; 

    SELECT GROUP_CONCAT(CONCAT(
      'WHEN s.strSensorHex = ''', strSensorHex, ''' THEN `', strSensorHex, '`') 
     ORDER BY strSensorHex SEPARATOR ' ') 
    INTO @sql 
    FROM sensoren; 

    SET @sql = CONCAT(
       'SELECT l.datetime, s.strSensorHex, s.strSensorBeschreibung, CASE ', @sql, 'END temperatur 
        FROM logtemp l CROSS JOIN sensoren s 
       ORDER BY l.datetime, s.strSensorBeschreibung' 
      ); 

    PREPARE stmt FROM @sql; 
    EXECUTE stmt; 
    DEALLOCATE PREPARE stmt; 
END$$ 
DELiMITER ; 

示例用法:

CALL sensortemp(); 

示例輸出:

 
|   DATETIME |  STRSENSORHEX | STRSENSORBESCHREIBUNG | TEMPERATUR | 
|---------------------|------------------|-----------------------|------------| 
| 2013-11-01 12:58:01 | 0400080224D59710 |   Testsensor 1 |  25.75 | 
| 2013-11-01 12:58:01 | CA00080224DDD010 |   Testsensor 2 |  24.19 | 
| 2013-11-01 12:58:01 | 5600080224E7FE10 |   Testsensor 3 |  24.31 | 
| 2013-11-01 12:58:01 | 0500080224D40B10 |   Testsensor 4 |  24.44 | 
| 2013-11-01 12:59:03 | 0400080224D59710 |   Testsensor 1 |  25.81 | 
| 2013-11-01 12:59:03 | CA00080224DDD010 |   Testsensor 2 |  24.19 | 
| 2013-11-01 12:59:03 | 5600080224E7FE10 |   Testsensor 3 |  24.31 | 
| 2013-11-01 12:59:03 | 0500080224D40B10 |   Testsensor 4 |  24.44 | 
| 2013-11-01 13:00:05 | 0400080224D59710 |   Testsensor 1 |  25.94 | 
| 2013-11-01 13:00:05 | CA00080224DDD010 |   Testsensor 2 |  24.25 | 
| 2013-11-01 13:00:05 | 5600080224E7FE10 |   Testsensor 3 |  24.38 | 
| 2013-11-01 13:00:05 | 0500080224D40B10 |   Testsensor 4 |  24.44 | 
... 

這裏是SQLFiddle demo


UPDATE:根據您的意見:您可以使用上述代碼,以幫助您建立一個視圖(基本上是戈登·利諾夫在他的回答提出)的定義。視圖的定義可能看起來像

CREATE VIEW vw_sensorentemp AS 
    SELECT l.datetime, s.strSensorHex, s.strSensorBeschreibung, 
     CASE s.strSensorHex 
      WHEN '0400080224D59710' THEN `0400080224D59710` 
      WHEN '0500080224D40B10' THEN `0500080224D40B10` 
      WHEN '5600080224E7FE10' THEN `5600080224E7FE10` 
      WHEN 'CA00080224DDD010' THEN `CA00080224DDD010` 
     END temperatur 
    FROM logtemp l CROSS JOIN sensoren s; 

現在你可以用它來結果不同

SELECT * 
    FROM vw_sensorentemp 
ORDER BY strSensorBeschreibung DESC; 

排序或與其他表連接。

注意:您必須在每次添加新的或刪除某些傳感器時更新視圖的定義。

這裏是SQLFiddle該場景的工作演示。

+0

存儲過程完美(僅小數位不限於兩個 - > 2013-11-01 12:58:01 | CA00080224DDD010 | Testsensor 2 | 24.190000534057617 |)。但是,如果可能的話,我更希望能夠將數據與其他數據一起加入或將其與其他數據分類。不幸的是,戈登的建議不起作用。 – Piet

+0

@Piet在我的示例中,小數位數是有限的,因爲我使用了'decimal(19,2)'數據類型而不是'float'。這僅僅是爲了舉例。它將完美地與浮動工作。如果可能的話,用於加入和更改排序順序的用例是有限的(在現實生活中通常是這樣),您可以通過傳遞適當的參數並動態構造正確的查詢字符串來擴展程序以使用動態SQL處理這些個案 – peterm

+0

@Piet如果我將數據類型更改爲十進制(19,2),則可以使用視圖方法查看更新後的答案 – peterm

0

這是有點長了評論,但是它包含了解決這個問題的兩種思路。

雖然我BarMar的評論表示贊同,我認識到,在現實世界中,事情可能不那麼容易定義。

定義已知列表傳感器的查詢不是問題。喜歡的東西:

select DATETIME, s.strSensorHex, s.strSensorBeschreibung, 
     (case when s.strSensorHex = '0400080224D59710' then lt.`0400080224D59710` 
      . . . 
     end) as Temperatur 
from logtemp lt cross join 
    sensoren s; 

傳感器列表中的一系列的case聲明when語句是固定的。令人高興的是,你可以把它放在一個視圖中,只要在它之前放置一條create view <blah> as聲明即可。

問題是添加一個新的傳感器。該視圖不是動態的,並且不能動態地理解新的傳感器值。 。 。但是,您可以使用準備好的語句來創建新的case子句的SQL以合併邏輯。

我的第一個建議是,您創建一個存儲過程來處理添加新傳感器的過程。這個存儲過程的一部分是使用準備語句重新創建視圖以重新定義視圖。

另一種可行的方法是採用審計表方法。將insert觸發器添加到logtemp表。此插入觸發器會將行插入另一個表中,每個傳感器只有一行。您可能還需要一個update觸發器。

+0

不幸的是,這個建議不起作用。 mysql> select DATETIME,s.strSensorHex,s.strSensorBeschreibung - >(case s.strSensorHex ='0400080224D59710'then lt.0400080224D59710' - > end)as temptemur - > from logtemp lt cross join sensoren s; 錯誤1305(42000):功能s.strSensorBeschreibung不存在 – Piet