3

プロジェクトの状態を記録するテーブルがあります。

CREATE TABLE `project_states` (
    `id` INT(10) NOT NULL AUTO_INCREMENT,
    `state_id` INT(10) NULL DEFAULT NULL,
    `project_id` INT(10) NULL DEFAULT NULL,
    `created_at` TIMESTAMP NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB

いくつかの偽のデータ:

    id  | state_id | project_id | created_at
-----------------------------------------------------
     1  |   2      |   8        | 2014-05-27 10:58:12   
     2  |   3      |   8        | 2014-05-27 11:10:34
     3  |   8      |   8        | 2014-05-27 11:56:48
     4  |   2      |  10        | 2014-05-27 11:08:34
     5  |   4      |  10        | 2014-05-27 11:59:01

2 つの状態 (たとえば、2 と 8) の間の時差を取得しようとしていますが、両方の状態を持つプロジェクトに対してのみです。この場合、プロジェクト 8 のみです (10 には状態 8 がないため)。

これまでのところ、基準に一致するプロジェクト (1 つだけでなく両方の値を持つ) を選択することができましたが、このクエリは、一致した各プロジェクトの結果のタプルを返します。

SELECT t.*
   FROM (
     SELECT ps.*
     FROM project_states ps
     WHERE ps.state_id IN (2,8) 
   ) as t
JOIN project_states pro ON pro.project_id = t.project_id
WHERE pro.state_id = 8

正しく返されます:

    id  | state_id | project_id | created_at
-----------------------------------------------------
     1  |   2      |   8        | 2014-05-27 10:58:12   
     3  |   8      |   8        | 2014-05-27 11:56:48

欠落している状態を他のプロジェクトに追加すると、結果の新しいタプルが返されるので、うまくいくと確信しています。

    id  | state_id | project_id | created_at
-----------------------------------------------------
     1  |   2      |   8        | 2014-05-27 10:58:12   
     3  |   8      |   8        | 2014-05-27 11:56:48
     4  |   2      |  10        | 2014-05-27 11:08:34
     6  |   8      |  10        | 2014-05-27 12:03:08

でも時差ってどうやって計算するの?私はPHPを使用しており、project_idで結果をループして差計算できることはわかっていますが、次のような結果をもたらす純粋なSQLソリューションがあると思います。

project_id | difference
------------------------
     8     | 0000-00-00 01:02:00
    10     | 0000-00-00 01:05:26

実際、私の目標は、プロジェクトがこれら 2 つの選択された状態の間にある平均時間差を計算することです。そのため、すべてのレコードが 1 つの平均値に要約される可能性がありますが、それは後で理解する問題になるかもしれません。

4

4 に答える 4

1

状態が 2 つしかない場合は、単純な INNER JOIN を使用できます。そしてTIMESTAMPDIFF()を使用して、たとえば分単位で差を取得します。

SELECT p.project_id,
       TIMESTAMPDIFF(MINUTE,p.created_at,p1.created_at) 
          as state_minutes_diff

FROM project_states as p
JOIN project_states as p1 
  ON p.project_id=p1.project_id
     AND p1.state_id=8  

WHERE p.state_id=3

SQLFiddle demo

すべてのプロジェクトの平均を取得するには:

SELECT AVG(TIMESTAMPDIFF(MINUTE,p.created_at,p1.created_at))
          as AVG_state_minutes_diff
FROM project_states as p
JOIN project_states as p1 
  ON p.project_id=p1.project_id
     AND p1.state_id=8  
WHERE p.state_id=3

SQLFiddle demo

于 2014-05-27T13:42:17.237 に答える
1

実際には、適切な句JOINを指定することで問題を解決できるため、必要ありません。GROUP BY

SELECT
  SEC_TO_TIME(AVG(times.atime)) AS avg_time
FROM
  (SELECT
    project_id,
    TIMEDIFF(MAX(created_at), MIN(created_at)) AS atime
  FROM
    project_states
  WHERE
    state_id IN (2,8)
  GROUP BY
    project_id
  HAVING
    COUNT(DISTINCT id)>1) as times

遅かったようですが、せめて作ったフィドルのせいです

于 2014-05-27T13:43:13.760 に答える