2017-07-05 27 views
3

次のSQLクエリが必要です。私はSQLの初心者です。下の表は私が持っているデータの一例です。私は約3000万行の非常に大きなデータを持っており、以下の出力テーブルを取得するためのクエリを作成したいと考えています。SQLサーバー内の同じテーブルの異なる行からの計算を計算するSQLクエリ

Id  type  data   time 
----------------------------------------------------------- 
    1   30   3.9   15:50:10.660555 
    1   30   4.0   15:50:10.660777 
    1   70   11.5   15:50:10.797966 
    1   30   4.1   15:50:10.834444 
    1   70   12.6   15:50:10.853114 
    1   70   16.7   15:50:10.955086 
    1   30   5   15:50:10.99 
    11   30   3.8   15:50:11.660555 
    11   30   4.1   15:50:11.660777 
    11   70   12.5   15:50:11.797966 
    11   30   4.7   15:50:11.834444 
    11   70   12.68  15:50:11.853114 
    11   70   16.76  15:50:11.955086 
    11   30   5.1   15:50:11.99 

私は上記のような表を持っています。例えば、Id = 1の場合、15:50:10.797966の最初の型= 70のデータの場合、15:30でtype = 30のデータを取得する必要があります。 50:10.660777となるので、結果= 11.5/4.0を計算することができます。同様に、タイプ= 70の15:50:10.853114では、タイプ= 30のデータを15:50:10.834444にしたいので、結果は12.6/4.1です。

私は、出力は次のようになりたい:

Id   type   result    time 
------------------------------------------------------ 
1   70    11.5/4.0  15:50:10.797966 
1   70    12.6/4.1  15:50:10.853114 
1   70    16.7/4.1  15:50:10.955086 
11   70    12.5/4.1  15:50:11.797966 
11   70    12.68/4.7  15:50:11.853114 
11   70    16.76/4.7  15:50:11.955086 

私はpyodbcを使用してpythonでこれらのSQLクエリを実行できるようにしたいと思います。

ご協力いただければ幸いです!前もって感謝します!!

+0

実際に使用しているmysqlとpostgresqlの両方にタグを付けましたか?彼らはさまざまな機能を持っているので、どのデータベースが使われているかによって答えが異なるかもしれません。また、使用しているデータベースのバージョンを指定してください。 – harmic

+0

@harmic:私はお詫び申し上げますが、実際にはSQLサーバ2017です。 – Gingerbread

+0

'time'に' date'コンポーネントはありませんか? –

答えて

1

id = 70の前にtype = 30 rowよりも前にあると仮定すると、outer applyを使用して、これを行うことができます。各タイプ= 70行の前にtype = 30の時間を取得し、

SELECT x.id, 
     x.type, 
     x.time, 
     x.data*1.0/t.data as result 
FROM 
    (SELECT t.*,t1.maxtime_before 
    FROM t 
    OUTER APPLY 
    (SELECT max(time) AS maxtime_before 
     FROM t t1 
     WHERE t1.id=t.id AND t1.type=30 AND t1.time<t.time) t1 
    WHERE type = 70 
) x 
JOIN t ON t.id=x.id AND t.time=x.maxtime_before 

何行がタイプと存在しない場合= 30種類= 70行の前に、あなたは

WITH x AS 
    (SELECT t.*, 
      t1.maxtime_before 
    FROM t 
    OUTER APPLY 
    (SELECT max(time) AS maxtime_before 
     FROM t t1 
     WHERE t1.id=t.id AND t1.type=30 AND t1.time<t.time) t1 
    WHERE type = 70 
) 
SELECT x.id, 
     x.type, 
     x.time, 
     x.data*1.0/t.data as resullt 
FROM t 
JOIN x ON t.id=x.id AND t.time=x.maxtime_before 
UNION ALL 
SELECT id, 
     type, 
     time, 
     NULL 
FROM x 
WHERE maxtime_before IS NULL 

Sample Demo

いずれかを使用して、結果の欄にその時間null値を表示することができそれより多くの方法は、id = 30行の実行最大時間を追跡するために、ウィンドウ関数maxを使用しています。

WITH x AS 
    (SELECT t.*, 
      MAX(CASE WHEN type=30 THEN time END) OVER(PARTITION BY id ORDER BY time) AS running_max 
    FROM t 
) 
SELECT x.id, 
     x.type, 
     x.time, 
     x.data*1.0/t.data as result 
FROM x 
JOIN t ON t.id=x.id AND t.time=x.running_max 
WHERE x.type=70 
UNION ALL 
SELECT id, 
     type, 
     time, 
     NULL 
FROM x 
WHERE running_max IS NULL 
+0

ありがとう!これはうまくいった! :D – Gingerbread

1

これは、ウィンドウ機能のみで行うことができます。

各行について、以前のタイプと値を取得します。また、それらをグループとして識別できるように70年代を列挙します(これは累積合計で行うことができます)。

次の手順では、partitioned maxを使用して型を取得し、最後に計算を行います。

select t.*, 
     data/data_30 as result 
from (select t.*, 
      max(case when prev_type = 30 then prev_data end) over (partition by id, grp) as data_30 
     from (select t.*, 
        sum(case when type <> 70 then 1 else 0 end) over (partition by id order by time) as grp, 
        lag(type) over (partition by id order by time) as prev_type, 
        lag(data) over (partition by id order by time) as prev_data 
      from t 
      where type in (30, 70) 
      ) t 
    ) t; 

これの興味深い側面の1つです。タイプを30と70に限定することによって、70の各グループの直前に30があることを保証します。

+0

ありがとうございました!これはうまくいった! :D – Gingerbread

+0

@Gingerbread。 。 。これは 'cross apply'を使った方がはるかに効率的です。 –

関連する問題