3

데이터베이스의 풀 온도 데이터를 사용하여 Annotation Chart을 만들고 싶습니다.Google Charts API DataTable 만들기 온도와 ID 데이터베이스에서

DROP TABLE IF EXISTS `temperatures`; 
DROP TABLE IF EXISTS `pools`; 

CREATE TABLE `pools` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, 
    `created_at` timestamp NULL DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 

CREATE TABLE `temperatures` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `pool_id` int(10) unsigned NOT NULL, 
    `temperature` double(8,1) NOT NULL, 
    `created_at` timestamp NULL DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `temperatures_pool_id_foreign` (`pool_id`), 
    CONSTRAINT `temperatures_pool_id_foreign` FOREIGN KEY (`pool_id`) REFERENCES `pools` (`id`) ON DELETE CASCADE 
) ENGINE=InnoDB AUTO_INCREMENT=3173 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 

INSERT INTO `pools` (`id`, `name`, `created_at`) 
VALUES 
    (1,'Pool #1','2017-04-08 22:48:03'), 
    (2,'Pool #2','2017-04-08 22:48:03'), 
    (3,'Pool #3','2017-04-08 22:48:03'); 

INSERT INTO `temperatures` (`id`, `pool_id`, `temperature`, `created_at`) 
VALUES 
    (31,1,100.1,'2017-04-09 02:44:56'), 
    (32,2,104.2,'2017-04-09 02:44:56'), 
    (33,3,97.0,'2017-04-09 02:44:56'), 
    (34,1,100.1,'2017-04-09 03:00:04'), 
    (35,2,98.4,'2017-04-09 03:00:04'), 
    (36,3,96.6,'2017-04-09 03:00:04'), 
    (37,1,100.1,'2017-04-09 03:37:13'), 
    (38,2,101.8,'2017-04-09 03:37:13'), 
    (39,3,96.4,'2017-04-09 03:37:13'), 
    (40,1,100.1,'2017-04-09 04:00:04'), 
    (41,2,101.8,'2017-04-09 04:00:04'), 
    (42,3,96.5,'2017-04-09 04:00:04'), 
    (43,1,100.1,'2017-04-09 05:00:04'), 
    (44,2,101.8,'2017-04-09 05:00:04'); 

좋아, 기본적으로, 나는 반환하는 컨트롤러를 생성하고 있습니다 : 데이터베이스 구조 here on sqlfiddle 또는 here on rextester 좀 걸릴 수 있지만, 당신에게 클릭을 저장, 여기에 내가 함께 일하고 있어요 구조입니다 제대로과 같이) 아약스와 google.visualization.DataTable (함께 사용하기위한 JSON 포맷 :

var data = new google.visualization.DataTable(); 
data.addColumn('date', 'Date'); 
data.addColumn('number', 'Kepler-22b mission'); 
data.addColumn('string', 'Kepler title'); 
data.addColumn('string', 'Kepler text'); 
data.addColumn('number', 'Gliese 163 mission'); 
data.addColumn('string', 'Gliese title'); 
data.addColumn('string', 'Gliese text'); 
data.addRows([ 
    [new Date(2314, 2, 15), 12400, undefined, undefined, 
          10645, undefined, undefined], 
    [new Date(2314, 2, 16), 24045, 'Lalibertines', 'First encounter', 
          12374, undefined, undefined], 
    [new Date(2314, 2, 17), 35022, 'Lalibertines', 'They are very tall', 
          15766, 'Gallantors', 'First Encounter'], 
    [new Date(2314, 2, 18), 12284, 'Lalibertines', 'Attack on our crew!', 
          34334, 'Gallantors', 'Statement of shared principles'], 
    [new Date(2314, 2, 19), 8476, 'Lalibertines', 'Heavy casualties', 
          66467, 'Gallantors', 'Mysteries revealed'], 
    [new Date(2314, 2, 20), 0, 'Lalibertines', 'All crew lost', 
          79463, 'Gallantors', 'Omniscience achieved'] 
]); 

var chart = new google.visualization.AnnotationChart(document.getElementById('chart_div')); 
: 문서에서 찾고 물론

var jsonData = $.ajax({ 
    url: "/data/pool-temperature-timeline", 
    dataType: "json", 
    async: false 
}).responseText; 

data = new google.visualization.DataTable(jsonData); 
chart.draw(data, options); 

, 주석 차트는이 형식을 따를 것을 기대하고있다

오른쪽의 설정이므로 지금 질문이옵니다. 1) 동일한 datetime에 대해 풀 1, 2 및 3에 대한 온도 데이터가 항상 있습니다 (데이터 세트가 주어진 타임 스탬프에 대해 완료되지 않을까 우려합니다). 영리한 쿼리를 사용하여 SQL 계층부터 구성해야합니까? 또는 foreach 루프를 사용하여 컨트롤러에서 구성합니까?

$dataTable->addRow(['created_at', 
    'temperature1', 'title1', 'text1', 
    'temperature2', 'title2', 'text2', 
    'temperature2', 'title2', 'text2', 
]); 

내가 영리 쿼리가 컨트롤러 논리와 foreach는 루프의 무리를하고 피하기 위해 갈 수있는 좋은 방법이 될 것입니다 볼 수 있습니다 : 이것은 내가 위해 노력하고있어 목표입니다. 데이터가 열에 정리 된 경우 다음과 같습니다.

created_at, pool_1_temperature, pool_2_temperature, pool_3_temperature 
------------------------------------------------ 
2017-04-09 02:44:56, 100.1, 104.2, 97.0 
2017-04-09 03:00:04, 100.1, 98.4, 96.6 
2017-04-09 03:37:13, 100.1, 101.8, 96.4 

그런 다음이를 통해 쉽게 데이터 테이블을 만들 수 있습니다. 나는 MySQL에서 이것을하는 방법이나 비록 그것이 좋은 생각인지 모르겠다.

시간을내어 주셔서 감사 드리며 사전에 도움을 주셔서 감사합니다. 내가 충분히 명확했으면 좋겠다.

추신. 나는 지금까지 건너 왔던 가장 가까운 것이 Mysql query to dynamically convert rows to columns이라고 생각한다. 나는 ...이 좀 더 놀러 갈거야

답변

0

너무 오래 날짜,
당신에 대해 걱정할 필요가 없습니다는 ... X 축 (첫 번째 열)로

온도 데이터를 차트와 같은

그것을 해결할 수있을 것 같은 날짜

에 대한 풀 1, 2, 3 항상있다, 다음과 유사한 쿼리를 사용할 수 있습니다 .. .

select 
    created_at, 
    case when 
    pool_id = 1 
    then 
    temperature 
    else 
    null 
    end pool_1, 
    case when 
    pool_id = 2 
    then 
    temperature 
    else 
    null 
    end pool_2, 
    case when 
    pool_id = 3 
    then 
    temperature 
    else 
    null 
    end pool_3 
from 
    temperatures 

나는 null를 반환하는 것은에서

+0

일반적으로이 규칙을 사용하면 서버에서 처리 할 수있는 프로세스가 많을수록 페이지로드 속도가 빨라집니다. 가능한 한 많은 논리를 SQL, Java 스크립트로 푸시하는 것이 좋습니다. . – WhiteHat

+0

나는 이것을 매우 고맙게 생각한다. 그것은 내 차트를 어떻게 처리 할 것인지에 대해 생각하게했다. 차트가 자체적으로 세부 사항 중 일부를 작동시킬 수 있다는 것이 옳았습니다. 저장 프로 시저가 필요한 미친 쿼리에서이를 처리하는 대신 루프 및 array_pad()를 사용하여 데이터를 정리했습니다. 곧 내 자신의 질문에 대답하려고 ... 다시 한번 감사드립니다! 그것은 올바른 길로 나를 잡았어. – dhildreth

0

를 작동하는지
그래서 나는 확실하지 않다는 SQL

를 확인할 수 없습니다, 일을 제공하는 SQL 링크 중 하나를 얻을 수 없습니다 데이터가 동적인지 확인하기 위해 미래에 다른 풀이 추가 될 경우 array_pad()을 사용하여 패딩 된 배열로 이동하고 온도 데이터 집합을 순환하여 내가가는대로 정렬하기로 결정했습니다. 또한 Google 데이터 테이블을 다루기 쉽게 만든 Lavacharts을 사용했습니다.그래서, 여기에 (주석 필드를 추가하는 데 필요한 참고, 더 많은 작업) 내 코드입니다 :

$dataTable = \Lava::DataTable(); 
$dataTable->addDateTimeColumn('DateTime'); 

// Add data column for each pool 
$pools = \App\Pool::get(); 
foreach($pools as $pool) { 
    $p = "Pool $pool->id"; 
    $dataTable->addNumberColumn("$p Temp"); 

    // TODO: Create annotate fields for min and max temperatures 
    // For this, we'll need to do some clever padding using array_pad() 
    // and more clever index incrementing in the for() loop below. 
    // Perhaps it's best to calculate and prepare in the temperatures query? 
    //$dataTable->addStringColumn("$p Title"); 
    //$dataTable->addStringColumn("$p Text"); 
} 

// Gather all the temperature data we wish to display. A year ought to be enough. 
// At one hour updates, that makes for about 8,766 datapoints. 
$temperatures = \App\Temperature::where('created_at', '>=', \Carbon\Carbon::now()->subYear()) 
    ->orderBy('created_at', 'desc') 
    ->orderBy('pool_id', 'asc')->get(); 

// Grab all the timestamps and organize into an array 
$created_ats = \App\Temperature::groupBy('created_at')->pluck('created_at'); 

// Let's go through each datetime field and collect all temperatures recorded on that datetime. 
// Then, let's store those temperatures into the appropriate index of the data row. 
foreach($created_ats as $created_at) { 
    $dataRow = [$created_at]; // Start the array off by adding date to beginning 
    $dataRow = array_pad($dataRow, 1 + count($pools), null); // +1 to account for $created_at column 
    //$dataRow = array_pad($dataRow, 1 + (count($pools) * 3), null); // TODO: multiply by 3 for annotation fields 

    // Start going through each temperature recording and assign to proper spot in dataRow array 
    // If temperature is not found for the datetime, the array_pad() above already accounts for null 
    // in that index. Note, the created_at comparison only accounts for the hour, not seconds or minutes. 
    // TODO: Implement min and max temperature annotations. 
    //$maxTemperature = 0; 
    //$minTemperature = 999; 
    foreach($temperatures as $temperature) { 
     // TODO: Implement min and max temperature annotations. 
     //$maxTemperature = ($temperature->temperature >= $maxTemperature) ? $temperature->temperature : $maxTemperature; 
     //$minTemperature = ($temperature->temperature <= $minTemperature) ? $temperature->temperature : $minTemperature; 

     // Compare date and hour, then assign to appropriate index of the data row according to pool id. 
     // ie. Pool ID #1 needs to be placed in [1], Pool ID #2 in [2] and so forth. Remember, [0] is date. 
     if ($temperature->created_at->format('Y-m-d H') == $created_at->format('Y-m-d H')) { 
      for ($i = 1; $i <= count($pools); $i++) { 
       if($temperature->pool_id == $i) { 
        $dataRow[$i] = $temperature->temperature; 
       } 
      } 
     } 
    } 

    // We've gone through all temperatures for this created_at datetime. 
    // Add the resulting dataRow to the dataTable. 
    $dataTable->addRow($dataRow); 
} 

// What we're left with is a bunch of rows that look like this! 
// TODO: Add annoation fields for min and max temperatures. 
// $dataTable->addRow(['created_at', 
// 'temperature1', 
// 'temperature2', 
// 'temperature2' 
// ]); 
$jsonData = $dataTable->toJson(); 

// At this point, return $jsonData for use with google.visualization.DataTable(jsonData); 
// Or, cache it and then return it, or whatever. 

이 (뷰에서 렌더링 할 때 약간의 시간이 걸릴 것으로 보인다 나는이 데이터를 캐싱 추천 할 것입니다 ~ 1.9s를). 그래서, 아마도 가장 빠른 방법은 아니지만, 그것은 나를위한 속임수입니다. 더 자세히 살펴보고 다른 최적화를 찾는 것이 흥미로울 것입니다. 지금은 그걸로 행복합니다.