我正在使用postgres SQL数据库,将军事时间存储为characers(不要问......),我需要更新一个列,该列将时间添加/减去一个时间本身的列。有些列只存储小时和分钟(HHMM或1005)以及一些商店小时,分钟和秒,作为时间戳...所以我留下了解析和提取数据。
例如;列TaxiTime
只存储小时和分钟,如下所示:
1005
或0050
第一次进入时间为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
我认为这会更新符合WHERE
和AND
条款标准的所有行(目前为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。将这些转换为time
或interval
类型的原因是因为启动时间可能是02:00或凌晨2点,如果zuluoffset是-5,那么我需要将其正确计算到21:00 ,不是-03:00。同样,其中一些列的类型为numeric
,而其他列character
...完全不在我手中,无法解决问题,所以我尽力了我一路走来。
我能够创建一个SQLFiddle(感谢那些建议它)并输入一些数据....虽然我的一些ETD值应该是0000
并且如果我做SELECT
在小提琴中,它们以0
的形式返回。无论如何,这里是SQL Fiddle。
答案 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')
您应该开始使用timestamp
,time
和interval
。这将是正义的道路。但你似乎知道这一点
既然你被困在你不幸的设置中,我也会帮助黑暗的一面。我很灵活。 :)(自我报价!)
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;
应用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)
没有必要进行字符串修改。使用extract
或date_part
和date_trunc
函数获取部分时间戳。当您要存储部分时间戳(如小时+天+秒)时,请根据需要使用time
或interval
数据类型。
我没有尝试编写替换,因为您没有发布您正在操作的数据/表,或者清楚地解释了整个查询应该做什么。我强烈怀疑当你摆脱字符串操作以支持正确的日期/时间处理函数时,你会有更好的结果。
答案 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
此外,为了排除故障,请将整个查询作为选择而不是更新运行。它会帮助你了解正在发生的事情。