1

私は軍事時間を文字として格納するpostgres SQLデータベースを使用しています(質問しないでください...)。時間そのものである列に時間を加算/減算する列を更新する必要があります。時間と分 (HHMM または 1005) のみを格納する列もあれば、タイムスタンプとして時間、分、秒を格納する列もあります。

例えば; 列TaxiTimeには時間と分のみが格納され 1005ます0050。たとえば、最初のエントリでは 10 時間 5 分、2 番目のエントリでは 0 時間 50 分になります。

私はpostgresqlは初めてですが、SQLは初めてなので、このクエリを作成することができました:

UPDATE "myTable".tgtplsel ts
SET etd = subquery.new_etd
FROM((SELECT 
        replace(((((interval '1 hours' * substring(starttime, 1, 2)::integer) +
        (interval '1 minutes' * substring(starttime, 3, 2)::integer)) + 

        ((interval '1 hours' * ((SELECT zuluoffset FROM "myTable".airports WHERE name = 'KABC'))) +
        (interval '1 minutes' * 0) +
        (interval '1 seconds' * 0))) +
        ((interval '1 hours' * substring(ts.taxidelay, 1, 2)::integer) +
        (interval '1 minutes' * substring(ts.taxidelay, 3, 2)::integer)) +

        ((interval '1 hours' * substring(ts.etd, 1, 2)::integer) +
        (interval '1 minutes' * substring(ts.etd, 3, 2)::integer))::time)::char(5), ':', '') as new_etd, ts.exerciseid

      FROM "myTable".tgtplsel as ts
      INNER JOIN "myTable".exerparm as ep ON ts.exerciseid = ep.exerciseid
      WHERE ts.exerciseid = 11
      AND ts.taxidelay is not null
      AND length(ts.taxidelay) > 0)) as subquery
WHERE ts.exerciseid = subquery.exerciseid 
AND ts.exerciseid = 11
AND ts.taxidelay is not null
AND length(ts.taxidelay) > 0

WHEREこれにより、 and句の基準を満たしたすべての行 (現在は 16 行) が更新されると思っていましたが、AND間違っていました。これにより、この基準を満たすすべてのレコードが更新されますが、サブクエリの FIRST 値のみで更新されます。なんで?

サブクエリ自体は、正しく計算された 16 行を返します。例:

0245
1050
0920
0345
1210
etc.

しかし、それをUPDATEステートメントにすると、16 行すべてが0245.

なんで?さらに重要なことに、各行を正しい値で更新するにはどうすればよいですか?

アップデート

最初に、すべての情報を提供できなかったことをお詫びします....仕事の帰りにこれをまとめて急いでいました...今....いくつかの質問に答えるために...
PostgreSQLのバージョンは8.3です.3
"myTable" は実際のスキーマ名ではありませんが、元の名前を別のものに置き換える必要がありました。

ここで、私が達成しようとしていることについてもう少し詳しく説明します。テーブルのETD列を、tgtplsel他のいくつかのフィールドから計算された値で更新しようとしています。この新しい値を生成するために使用している式は次のとおりです。

ETD = ((starttime - zuluoffset) + taxidelay + ETD)

したがって、ETD が 00:30、starttime が 23:00、zuluoffset が -5、taxidelay が 0005 の場合、新しい ETD は ((23:00 - (-5)) + 00:05 + 00:30 になります。 )または18:35。これらをtimeorinterval型に変換する理由は、開始時間が 02:00 または午前 2 時である可能性があり、zuluoffset が -5 の場合、-03:00 ではなく 21:00 に正しく計算する必要があるためです。繰り返しますが、これらの列のいくつかはタイプのものですnumericが、他のものはcharacter...完全に私の手に負えず、修正するために何もできないので、私はそれを回避するために最善を尽くしています.

私はSQLFiddleを作成し(それを提案した人に感謝します)、いくつかのデータを入力することができました....私のETD値のいくつかはそうであるはずでしたが、フィドルで0000aを実行すると、それらは. とにかく、これがSQL Fiddleです。SELECT0

4

3 に答える 3

1

基本クエリ

複雑な計算は別として、 を大幅に簡素化できますUPDATE。サブクエリは彼女を必要としませんでした:

UPDATE "myTable".tgtplsel ts
SET    etd = <complex calculation>
FROM   "myTable".exerparm ep
WHERE  ep.exerciseid = ts.exerciseid 
AND    ts.exerciseid = 11
AND    ts.taxidelay is not null
AND    length(ts.taxidelay) > 0

そして真剣に?「myTable」はスキーマの名前ですか?

計算

あなたの巨大な表現 (aka <complex calculation>):

TL;DR

次のように書き換えることができます。

 to_char( to_timestamp(ep.starttime, 'HH24mi')::time
          + (SELECT interval '1h' * zuluoffset
             FROM "myTable".airports WHERE name = 'KABC')
          + to_timestamp(ts.taxidelay, 'HH24mi')::time::interval      
          + to_timestamp(ts.etd, 'HH24mi')::time::interval
         , 'HH24mi')
  • で操作する必要がtimestampありtimeますinterval。それが正道だ。しかし、あなたはそれを知っているようです。
    あなたが不幸な設定で立ち往生しているので、私もダークサイドを手伝います. 私は柔軟です。:) (自己引用!)

  • to_timestamp()timeを入力として取ることができます。年 1が先頭に追加されますが、これはここでは関係ありませtimeinterval

  • 関数to_char()を使用して を にinterval戻しtextます。

機能

暗黒面での生活を少し明るくするために、秒の有無にかかわらず機能するこれらの変換関数をいくつか作成します。

「軍事時間」を時間に変換します。

CREATE FUNCTION f_mt2time(text)
  RETURNS time AS
$func$
SELECT CASE WHEN length($1) = 4
        THEN to_timestamp($1, 'HH24mi')::time
        ELSE to_timestamp($1, 'HH24miss')::time
       END
$func$ LANGUAGE sql IMMUTABLE;

時間を「軍事時間」に変換します。

CREATE FUNCTION f_time2mt(time)
  RETURNS text AS
$func$
SELECT CASE WHEN extract(sec FROM $1) = 0
        THEN to_char($1, 'HH24MI')
        ELSE to_char($1, 'HH24MISS')
       END
$func$ LANGUAGE sql IMMUTABLE;

->関数のSQLfiddleデモ

すべてをまとめる

aux を適用します。関数を使用して、定数サブクエリをzuluoffset式からFROMリストに抽出します。より明確に、より速く:

UPDATE "myTable".tgtplsel ts
SET    etd = f_time2mt(
                f_mt2time(ep.starttime)
              + z.zulu
              + f_mt2time(ts.taxidelay)::interval      
              + f_mt2time(ts.etd)::interval)
FROM   "myTable".exerparm ep
CROSS   JOIN (
   SELECT interval '1h' * zuluoffset AS zulu
   FROM   "myTable".airports
   WHERE  name = 'KABC'
   ) z
WHERE  ep.exerciseid = ts.exerciseid 
AND    ts.exerciseid = 11
AND    ts.taxidelay is not null
AND    length(ts.taxidelay) > 0;

はるかに良くなりました。

于 2013-05-07T00:05:56.843 に答える
0

その文字列マングリングは必要ありません。extractordate_partおよび関数を使用してdate_trunc、タイムスタンプの一部を取得します。時間 + 日 + 秒などの部分的なタイムスタンプを保存する場合は、必要に応じてtimeまたはのデータ型を使用します。interval

操作しているデータ/テーブルを投稿していないか、クエリ全体が何をすべきかを明確に説明していないため、代替を作成しようとはしていません。ただし、適切な日付/時刻処理関数を優先して文字列操作を取り除くと、より良い結果が得られると強く思います。

于 2013-05-07T00:02:33.720 に答える
-1

変更することをお勧めします:

AND length(ts.taxidelay) > 0)) as subquery
WHERE ts.exerciseid = subquery.exerciseid 

AND length(ts.taxidelay) > 0)) as subquery
ON ts.exerciseid = subquery.exerciseid 

また、トラブルシューティングのために、クエリ全体を更新ではなく選択として実行します。何が起こっているかを確認するのに役立ちます。

于 2013-05-06T23:36:33.780 に答える