在 SELECT 中显示每个位置的本地时区
Display local time zone for each location in SELECT
我有 table 次火车旅行,使用以下示例代码:
CREATE TABLE train_rides (
trip_id bigserial PRIMARY KEY,
origination text NOT NULL,
destination text NOT NULL,
departure timestamp with time zone NOT NULL,
arrival timestamp with time zone NOT NULL
);
INSERT INTO train_rides (origination, destination, departure, arrival)
VALUES
('Chicago', 'New York', '2017-11-13 21:30 CST', '2017-11-14 18:23 EST'),
('New York', 'New Orleans', '2017-11-15 14:15 EST', '2017-11-16 19:32 CST'),
('New Orleans', 'Los Angeles', '2017-11-17 13:45 CST', '2017-11-18 9:00 PST'),
('Los Angeles', 'San Francisco', '2017-11-19 10:10 PST', '2017-11-19 21:24 PST'),
('San Francisco', 'Denver', '2017-11-20 9:10 PST', '2017-11-21 18:38 MST'),
('Denver', 'Chicago', '2017-11-22 19:10 MST', '2017-11-23 14:50 CST');
当我运行针对此数据进行以下查询时:
SELECT origination || ' to ' || destination AS segment,
to_char(departure, 'YYYY-MM-DD HH12:MI a.m. TZ') AS departure,
to_char(arrival, 'YYYY-MM-DD HH12:MI a.m. TZ') AS arrival
FROM train_rides;
它给我以下输出:
--------------------------------------------------------------------------------------
| segment | departure | arrival |
--------------------------------------------------------------------------------------
| Chicago to New York | 2017-11-13 09:30 p.m. CST | 2017-11-14 05:23 p.m. CST |
| New York to New Orleans | 2017-11-15 01:15 p.m. CST | 2017-11-16 07:32 p.m. CST |
| New Orleans to Los Angeles | 2017-11-17 01:45 p.m. CST | 2017-11-18 11:00 a.m. CST |
| San Francisco to Denver | 2017-11-20 11:10 a.m. CST | 2017-11-21 07:38 p.m. CST |
| Denver to Chicago | 2017-11-22 08:10 p.m. CST | 2017-11-23 02:50 p.m. CST |
--------------------------------------------------------------------------------------
所有时间均以CST时区显示,以服务器时区设置为准。
首选输出
我想让输出反映每个出发城市或目的地城市的本地时区,如下所示:
--------------------------------------------------------------------------------------
| segment | departure | arrival |
--------------------------------------------------------------------------------------
| Chicago to New York | 2017-11-13 09:30 p.m. CST | 2017-11-14 06:23 p.m. EST |
| New York to New Orleans | 2017-11-15 02:15 p.m. EST | 2017-11-16 07:32 p.m. CST |
| New Orleans to Los Angeles | 2017-11-17 01:45 p.m. CST | 2017-11-18 09:00 a.m. PST |
| San Francisco to Denver | 2017-11-20 09:10 a.m. PST | 2017-11-21 06:38 p.m. MST |
| Denver to Chicago | 2017-11-22 07:10 p.m. MST | 2017-11-23 02:50 p.m. CST |
--------------------------------------------------------------------------------------
如何让每个时间都反映当地时区?例如,在上面的第一行中,芝加哥的出发将显示为 CST,纽约的到达将显示为 EST。
一个可能的解决方案是使用 AT TIME ZONE
限定符,也许使用这样的查找 table:
----------------------------
| city | local_tz |
----------------------------
| Chicago | CST |
| Denver | MST |
| Los Angeles | PST |
| New Orleans | CST |
| New York | EST |
| San Francisco | PST |
----------------------------
我曾考虑过使用 plpgsql 代码块构建动态查询,但那会非常混乱。我希望有一种简单、更优雅的方法来做到这一点。
我找到了获得预期结果的方法;这不是最优雅的方法,但确实有效。
首先,我在 train_rides table:
中添加了另外两列
-- Add columns to hold local times
ALTER TABLE train_rides
ADD COLUMN departure_local TIMESTAMP WITHOUT TIME ZONE,
ADD COLUMN arrival_local TIMESTAMP WITHOUT TIME ZONE;
然后我使用一堆代码(使用 not-so-elegant、brute-force 方法)填充本地出发列:
-- Update departures to reflect local times
UPDATE train_rides
SET departure_local = departure AT TIME ZONE 'US/Central'
WHERE origination = 'Chicago';
UPDATE train_rides
SET departure_local = departure AT TIME ZONE 'US/Mountain'
WHERE origination = 'Denver';
UPDATE train_rides
SET departure_local = departure AT TIME ZONE 'US/Pacific'
WHERE origination = 'Los Angeles';
UPDATE train_rides
SET departure_local = departure AT TIME ZONE 'US/Central'
WHERE origination = 'New Orleans';
UPDATE train_rides
SET departure_local = departure AT TIME ZONE 'US/Eastern'
WHERE origination = 'New York';
UPDATE train_rides
SET departure_local = departure AT TIME ZONE 'US/Pacific'
WHERE origination = 'San Francisco';
接下来,我以同样的方式填充本地到达:
-- Update arrivals to reflect local times
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE 'US/Central'
WHERE origination = 'Chicago';
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE 'US/Mountain'
WHERE origination = 'Denver';
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE 'US/Pacific'
WHERE origination = 'Los Angeles';
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE 'US/Central'
WHERE origination = 'New Orleans';
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE 'US/Eastern'
WHERE origination = 'New York';
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE 'US/Pacific'
WHERE origination = 'San Francisco';
最后,我可以使用一些 SQL 魔法来获得最终结果:
SELECT origination || ' to ' || destination AS segment,
to_char(departure_local, 'YYYY-MM-DD HH12:MI a.m. ') ||
(SELECT local_tz from local_timezones tz
WHERE tr.origination = tz.city) AS departure,
to_char(arrival_local, 'YYYY-MM-DD HH12:MI a.m. ') ||
(SELECT local_tz from local_timezones tz
WHERE tr.destination = tz.city) AS arrival
FROM train_rides tr;
如果有一种方法可以使用查找动态填充 AT TIME ZONE 参数,那么所有这些 UPDATE 语句都可以减少到只有两个。这种 brute-force 方法不能很好地扩展,因为我们必须为每个可能的城市手动编码。
除非,也就是说,有人知道更好的方法。
今天我了解了 SQL 子查询的强大功能,我脑子里的灯泡熄灭了。下面是两种更好的方法。
这两种方法都使用了以下名为 trains_local_timezones
:
的查找 table
-----------------------------------------
| city | timezone | tz_abbr |
-----------------------------------------
| Chicago | US/Central | CST |
| Denver | US/Mountain | MST |
| Los Angeles | US/Pacific | PST |
| New Orleans | US/Central | CST |
| New York | US/Eastern | EST |
| San Francisco | US/Pacific | PST |
-----------------------------------------
-- 更好的方法(这可以根据需要扩展)
-- Add columns to hold local times
ALTER TABLE train_rides
ADD COLUMN departure_local TIMESTAMP WITHOUT TIME ZONE,
ADD COLUMN arrival_local TIMESTAMP WITHOUT TIME ZONE;
-- Update departures to reflect local times
UPDATE train_rides
SET departure_local = departure AT TIME ZONE
(SELECT timezone from trains_local_timezones tz
WHERE origination = tz.city);
-- Update arrivals to reflect local times
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE
(SELECT timezone from trains_local_timezones tz
WHERE destination = tz.city);
SELECT origination || ' to ' || destination AS segment,
to_char(departure_local, 'YYYY-MM-DD HH12:MI AM ') ||
(SELECT tz_abbr from trains_local_timezones tz
WHERE tr.origination = tz.city) AS local_departure,
to_char(arrival_local, 'YYYY-MM-DD HH12:MI AM ') ||
(SELECT tz_abbr from trains_local_timezones tz
WHERE tr.destination = tz.city) AS local_arrival
FROM train_rides tr;
-- 最佳方式(不需要额外的列)
SELECT origination || ' to ' || destination AS segment,
to_char(departure AT TIME ZONE
(SELECT timezone from trains_local_timezones tz
WHERE origination = tz.city), 'YYYY-MM-DD HH12:MI AM ') ||
(SELECT tz_abbr from trains_local_timezones tz
WHERE tr.origination = tz.city) AS local_departure,
to_char(arrival AT TIME ZONE
(SELECT timezone from trains_local_timezones tz
WHERE destination = tz.city), 'YYYY-MM-DD HH12:MI AM ') ||
(SELECT tz_abbr from trains_local_timezones tz
WHERE tr.destination = tz.city) AS local_arrival
FROM train_rides tr;
我有 table 次火车旅行,使用以下示例代码:
CREATE TABLE train_rides (
trip_id bigserial PRIMARY KEY,
origination text NOT NULL,
destination text NOT NULL,
departure timestamp with time zone NOT NULL,
arrival timestamp with time zone NOT NULL
);
INSERT INTO train_rides (origination, destination, departure, arrival)
VALUES
('Chicago', 'New York', '2017-11-13 21:30 CST', '2017-11-14 18:23 EST'),
('New York', 'New Orleans', '2017-11-15 14:15 EST', '2017-11-16 19:32 CST'),
('New Orleans', 'Los Angeles', '2017-11-17 13:45 CST', '2017-11-18 9:00 PST'),
('Los Angeles', 'San Francisco', '2017-11-19 10:10 PST', '2017-11-19 21:24 PST'),
('San Francisco', 'Denver', '2017-11-20 9:10 PST', '2017-11-21 18:38 MST'),
('Denver', 'Chicago', '2017-11-22 19:10 MST', '2017-11-23 14:50 CST');
当我运行针对此数据进行以下查询时:
SELECT origination || ' to ' || destination AS segment,
to_char(departure, 'YYYY-MM-DD HH12:MI a.m. TZ') AS departure,
to_char(arrival, 'YYYY-MM-DD HH12:MI a.m. TZ') AS arrival
FROM train_rides;
它给我以下输出:
--------------------------------------------------------------------------------------
| segment | departure | arrival |
--------------------------------------------------------------------------------------
| Chicago to New York | 2017-11-13 09:30 p.m. CST | 2017-11-14 05:23 p.m. CST |
| New York to New Orleans | 2017-11-15 01:15 p.m. CST | 2017-11-16 07:32 p.m. CST |
| New Orleans to Los Angeles | 2017-11-17 01:45 p.m. CST | 2017-11-18 11:00 a.m. CST |
| San Francisco to Denver | 2017-11-20 11:10 a.m. CST | 2017-11-21 07:38 p.m. CST |
| Denver to Chicago | 2017-11-22 08:10 p.m. CST | 2017-11-23 02:50 p.m. CST |
--------------------------------------------------------------------------------------
所有时间均以CST时区显示,以服务器时区设置为准。
首选输出
我想让输出反映每个出发城市或目的地城市的本地时区,如下所示:
--------------------------------------------------------------------------------------
| segment | departure | arrival |
--------------------------------------------------------------------------------------
| Chicago to New York | 2017-11-13 09:30 p.m. CST | 2017-11-14 06:23 p.m. EST |
| New York to New Orleans | 2017-11-15 02:15 p.m. EST | 2017-11-16 07:32 p.m. CST |
| New Orleans to Los Angeles | 2017-11-17 01:45 p.m. CST | 2017-11-18 09:00 a.m. PST |
| San Francisco to Denver | 2017-11-20 09:10 a.m. PST | 2017-11-21 06:38 p.m. MST |
| Denver to Chicago | 2017-11-22 07:10 p.m. MST | 2017-11-23 02:50 p.m. CST |
--------------------------------------------------------------------------------------
如何让每个时间都反映当地时区?例如,在上面的第一行中,芝加哥的出发将显示为 CST,纽约的到达将显示为 EST。
一个可能的解决方案是使用 AT TIME ZONE
限定符,也许使用这样的查找 table:
----------------------------
| city | local_tz |
----------------------------
| Chicago | CST |
| Denver | MST |
| Los Angeles | PST |
| New Orleans | CST |
| New York | EST |
| San Francisco | PST |
----------------------------
我曾考虑过使用 plpgsql 代码块构建动态查询,但那会非常混乱。我希望有一种简单、更优雅的方法来做到这一点。
我找到了获得预期结果的方法;这不是最优雅的方法,但确实有效。
首先,我在 train_rides table:
中添加了另外两列-- Add columns to hold local times
ALTER TABLE train_rides
ADD COLUMN departure_local TIMESTAMP WITHOUT TIME ZONE,
ADD COLUMN arrival_local TIMESTAMP WITHOUT TIME ZONE;
然后我使用一堆代码(使用 not-so-elegant、brute-force 方法)填充本地出发列:
-- Update departures to reflect local times
UPDATE train_rides
SET departure_local = departure AT TIME ZONE 'US/Central'
WHERE origination = 'Chicago';
UPDATE train_rides
SET departure_local = departure AT TIME ZONE 'US/Mountain'
WHERE origination = 'Denver';
UPDATE train_rides
SET departure_local = departure AT TIME ZONE 'US/Pacific'
WHERE origination = 'Los Angeles';
UPDATE train_rides
SET departure_local = departure AT TIME ZONE 'US/Central'
WHERE origination = 'New Orleans';
UPDATE train_rides
SET departure_local = departure AT TIME ZONE 'US/Eastern'
WHERE origination = 'New York';
UPDATE train_rides
SET departure_local = departure AT TIME ZONE 'US/Pacific'
WHERE origination = 'San Francisco';
接下来,我以同样的方式填充本地到达:
-- Update arrivals to reflect local times
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE 'US/Central'
WHERE origination = 'Chicago';
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE 'US/Mountain'
WHERE origination = 'Denver';
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE 'US/Pacific'
WHERE origination = 'Los Angeles';
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE 'US/Central'
WHERE origination = 'New Orleans';
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE 'US/Eastern'
WHERE origination = 'New York';
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE 'US/Pacific'
WHERE origination = 'San Francisco';
最后,我可以使用一些 SQL 魔法来获得最终结果:
SELECT origination || ' to ' || destination AS segment,
to_char(departure_local, 'YYYY-MM-DD HH12:MI a.m. ') ||
(SELECT local_tz from local_timezones tz
WHERE tr.origination = tz.city) AS departure,
to_char(arrival_local, 'YYYY-MM-DD HH12:MI a.m. ') ||
(SELECT local_tz from local_timezones tz
WHERE tr.destination = tz.city) AS arrival
FROM train_rides tr;
如果有一种方法可以使用查找动态填充 AT TIME ZONE 参数,那么所有这些 UPDATE 语句都可以减少到只有两个。这种 brute-force 方法不能很好地扩展,因为我们必须为每个可能的城市手动编码。
除非,也就是说,有人知道更好的方法。
今天我了解了 SQL 子查询的强大功能,我脑子里的灯泡熄灭了。下面是两种更好的方法。
这两种方法都使用了以下名为 trains_local_timezones
:
-----------------------------------------
| city | timezone | tz_abbr |
-----------------------------------------
| Chicago | US/Central | CST |
| Denver | US/Mountain | MST |
| Los Angeles | US/Pacific | PST |
| New Orleans | US/Central | CST |
| New York | US/Eastern | EST |
| San Francisco | US/Pacific | PST |
-----------------------------------------
-- 更好的方法(这可以根据需要扩展)
-- Add columns to hold local times
ALTER TABLE train_rides
ADD COLUMN departure_local TIMESTAMP WITHOUT TIME ZONE,
ADD COLUMN arrival_local TIMESTAMP WITHOUT TIME ZONE;
-- Update departures to reflect local times
UPDATE train_rides
SET departure_local = departure AT TIME ZONE
(SELECT timezone from trains_local_timezones tz
WHERE origination = tz.city);
-- Update arrivals to reflect local times
UPDATE train_rides
SET arrival_local = arrival AT TIME ZONE
(SELECT timezone from trains_local_timezones tz
WHERE destination = tz.city);
SELECT origination || ' to ' || destination AS segment,
to_char(departure_local, 'YYYY-MM-DD HH12:MI AM ') ||
(SELECT tz_abbr from trains_local_timezones tz
WHERE tr.origination = tz.city) AS local_departure,
to_char(arrival_local, 'YYYY-MM-DD HH12:MI AM ') ||
(SELECT tz_abbr from trains_local_timezones tz
WHERE tr.destination = tz.city) AS local_arrival
FROM train_rides tr;
-- 最佳方式(不需要额外的列)
SELECT origination || ' to ' || destination AS segment,
to_char(departure AT TIME ZONE
(SELECT timezone from trains_local_timezones tz
WHERE origination = tz.city), 'YYYY-MM-DD HH12:MI AM ') ||
(SELECT tz_abbr from trains_local_timezones tz
WHERE tr.origination = tz.city) AS local_departure,
to_char(arrival AT TIME ZONE
(SELECT timezone from trains_local_timezones tz
WHERE destination = tz.city), 'YYYY-MM-DD HH12:MI AM ') ||
(SELECT tz_abbr from trains_local_timezones tz
WHERE tr.destination = tz.city) AS local_arrival
FROM train_rides tr;