动态创建时间戳

时间:2013-05-06 23:12:12

标签: sql postgresql

我正在使用postgres SQL数据库,将军事时间存储为characers(不要问......),我需要更新一个列,该列将时间添加/减去一个时间本身的列。有些列只存储小时和分钟(HHMM或1005)以及一些商店小时,分钟和秒,作为时间戳...所以我留下了解析和提取数据。

例如;列TaxiTime只存储小时和分钟,如下所示: 10050050第一次进入时间为10小时5分钟,第二次进入时间为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

我认为这会更新符合WHEREAND条款标准的所有行(目前为16个),但我错了。这将更新满足此条件的所有记录,但仅更新子查询的FIRST值。为什么呢?

子查询本身返回16行,正确计算,例如:

0245
1050
0920
0345
1210
etc.

但当我将其转换为UPDATE语句时,它会使用0245更新所有16行。

为什么呢?更重要的是,如何使用正确的值更新每一行?

更新

首先,我为没有提供所有信息而道歉......我在离开工作的路上把它扔在一起,匆匆忙忙......现在......回答一些问题...... /> PostgreSQL版本 8.3.3
" myTable的"不是真正的架构名称,但我必须用其他东西替换原件。

而且这里有一点关于我想要完成的事情:我试图更新ETD tgtplsel列表格,其值由几个其他字段计算得出。我们用来生成这个新值的公式是:

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

所以如果我的ETD是00:30,开始时间是23:00,zuluoffset是-5,而taxidelay是0005,那么新的ETD应该是((23:00 - ( - 5))+ 00:05 + 00:30)或18:35。将这些转换为timeinterval类型的原因是因为启动时间可能是02:00或凌晨2点,如果zuluoffset是-5,那么我需要将其正确计算到21:00 ,不是-03:00。同样,其中一些列的类型为numeric,而其他列character ...完全不在我手中,无法解决问题,所以我尽力了我一路走来。

我能够创建一个SQLFiddle(感谢那些建议它)并输入一些数据....虽然我的一些ETD值应该是0000并且如果我做SELECT在小提琴中,它们以0的形式返回。无论如何,这里是SQL Fiddle

3 个答案:

答案 0 :(得分: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”是架构的名称吗?

计算

你的怪异表情(a.k.a。<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')
  • 您应该开始使用timestamptimeinterval。这将是正义的道路。但你似乎知道这一点 既然你被困在你不幸的设置中,我也会帮助黑暗的一面。我很灵活。 :)(自我报价!)

  • to_timestamp()可以输入time。它取决于 year 1 ,这与此无关,因为我们立即转向time(反过来可以转换为interval)。

  • 使用[{3}}功能将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;

to_char()

全部放在一起

应用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;

现在好多了。

答案 1 :(得分:0)

没有必要进行字符串修改。使用extractdate_partdate_trunc函数获取部分时间戳。当您要存储部分时间戳(如小时+天+秒)时,请根据需要使用timeinterval数据类型。

我没有尝试编写替换,因为您没有发布您正在操作的数据/表,或者清楚地解释了整个查询应该做什么。我强烈怀疑当你摆脱字符串操作以支持正确的日期/时间处理函数时,你会有更好的结果。

答案 2 :(得分:-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 

此外,为了排除故障,请将整个查询作为选择而不是更新运行。它会帮助你了解正在发生的事情。