Appearance
Implicit Casting Examples
This section shows some examples of queries in which an implicit cast converts a value or expression of a given data type to another data type.
Casts for Dates and Timestamps
The following example implicitly casts a TIMESTAMP
column (matchday
) to a character string in order to return the result of the SUBSTR
function.
premdb=# select matchday, substr(matchday,1,4) yr from match where htid=3 and atid=56;
matchday | yr
---------------------+------
2010-11-10 00:00:00 | 2010
(1 row)
The following example inserts a DATE
value into a TIMESTAMP
column:
premdb=# insert into match(matchday) select current_date;
INSERT 0 1
premdb=# select * from match where matchday=(select current_date);
seasonid | matchday | htid | atid | ftscore | htscore
----------+---------------------+--------+--------+---------+---------
[NULL] | 2020-09-25 00:00:00 | [NULL] | [NULL] | [NULL] | [NULL]
(1 row)
This example uses a table called chartime
, which contains four VARCHAR
columns. However, these columns contain VARCHAR
strings that represent TIME
, TIMESTAMP
, TIMESTAMPTZ
, and DATE
values.
premdb=# \d chartime
Table "public.chartime"
Column | Type | Modifiers
--------+-----------------------+-----------
c1 | character varying(12) |
c2 | character varying(24) |
c3 | character varying(24) |
c4 | character varying(10) |
Distribution: Hash (c1)
premdb=# select * from chartime;
c1 | c2 | c3 | c4
----------+---------------------+------------------------+------------
00:00:00 | 2012-12-22 00:00:00 | 2012-12-22 00:00:00-07 | 2012-12-22
12:55:00 | 2020-09-25 12:55:00 | 2020-09-25 12:55:00-07 | 2020-09-25
(2 rows)
Implicit casts make it possible to query and compare these columns directly with datetime functions such as EXTRACT
. For example:
premdb=# select extract(day from c2) from chartime;
date_part
-----------
25
22
(2 rows)
You can use an EXPLAIN
command with the VERBOSE
option to see the implicit cast on the c2
column in this example:
premdb=# explain (verbose) select extract(day from c2) from chartime;
QUERY PLAN
---------------------------------------------------------------------------------------------------------
id rows_planned mem_planned mem_actual workers node
1 100 8.00Mi H 0.00 all SELECT
(EXTRACT(day FROM chartime.c2::TIMESTAMPTZ))
distribute on (chartime.c1)
3 100 57.00Mi H 0.00 all SCAN chartime
(chartime.c2)
distribute on (chartime.c1)
...
A join condition between one a VARCHAR
column in the chartime
table and the match.matchday
TIMESTAMP
column also benefits from an implicit cast:
premdb=# select * from match, chartime where match.matchday=chartime.c2;
seasonid | matchday | htid | atid | ftscore | htscore | c1 | c2 | c3 | c4
----------+---------------------+------+------+---------+---------+----------+---------------------+------------------------+------------
21 | 2012-12-22 00:00:00 | 44 | 78 | 2-1 | 1-1 | 00:00:00 | 2012-12-22 00:00:00 | 2012-12-22 00:00:00-07 | 2012-12-22
21 | 2012-12-22 00:00:00 | 45 | 67 | 1-2 | 1-0 | 00:00:00 | 2012-12-22 00:00:00 | 2012-12-22 00:00:00-07 | 2012-12-22
21 | 2012-12-22 00:00:00 | 46 | 51 | 0-1 | 0-0 | 00:00:00 | 2012-12-22 00:00:00 | 2012-12-22 00:00:00-07 | 2012-12-22
...
Again you can use the EXPLAIN
command to see the implicit cast:
premdb=# explain select * from match, chartime where match.matchday=chartime.c2;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------
id rows_planned workers node
1 396783 all SELECT
10 396783 all INNER JOIN ON (chartime.c2::TIMESTAMP = match.matchday)
13 8812544 all |-SCAN match
| match.matchday = bloom(2) AND scan_constraints: min_max(match.matchday)
2 100 all |-BUILD
3 100 all DISTRIBUTE REPLICATE
5 100 all SCAN chartime
...
In this example, a VARCHAR
column contains a character string for a date. When the DATEADD
function is applied to this string, the highest type in the datetime hierarchy (TIMESTAMPTZ
) is used for the implicit cast:
premdb=# \d vardate
Table "public.vardate"
Column | Type | Modifiers
--------+-----------------------+-----------
c1 | character varying(10) |
Distribution: Hash (c1)
premdb=# insert into vardate values('2020-12-31');
INSERT 0 1
premdb=# select dateadd(month, 1, c1) from vardate;
dateadd
------------------------
2021-01-31 00:00:00-08
(1 row)
premdb=# explain verbose select dateadd(month, 1, c1) from vardate;
QUERY PLAN
---------------------------------------------------------------------------------------------------------
id rows_planned mem_planned mem_actual workers node
1 100 32.00Mi H 0.00 all SELECT
(DATEADD(month, $0, vardate.c1::TIMESTAMPTZ)
distribute on (vardate.c1)
3 100 57.00Mi H 0.00 all SCAN vardate
(vardate.c1)
distribute on (vardate.c1)
...
Numbers as Character Strings
When the CONCAT
function concatenates data with different types, the values are implicitly cast to VARCHAR
. In this case, teamid
and capacity
are integer columns:
premdb=# select concat(teamid,' ',name,' ',capacity) from team limit 3;
concat
-----------------------
37 Stoke City 27902
38 Sunderland 49000
39 Swansea City 20520
(3 rows)
premdb=# explain verbose select concat(teamid,' ',name,' ',capacity) from team limit 3;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------
id rows_planned mem_planned mem_actual workers node
1 3 32.98Mi H 0.00 single SELECT
(team.teamid::VARCHAR(6) || $0 || team.name || $1 || team.capacity::VARCHAR(11))
distribute single
2 3 4.00Mi H 0.00 single LIMIT $4
(team.teamid::VARCHAR(6) || $0 || team.name || $1 || team.capacity::VARCHAR(11))
distribute single
4 100 57.00Mi H 0.00 single SCAN team
(team.teamid, team.name, team.capacity)
distribute single
...
You can implicitly cast an integer column to a character string in order to apply a LIKE
condition:
premdb=# select * from team where capacity like '75%';
teamid | htid | atid | name | nickname | city | stadium | capacity
--------+------+------+-------------------+------------+------------+--------------+----------
25 | 26 | 75 | Manchester United | Red Devils | Manchester | Old Trafford | 75635
(1 row)
premdb=# explain select * from team where capacity like '75%';
QUERY PLAN
---------------------------------------------------------------------------
id rows_planned workers node
1 1 single SELECT
3 1 single SCAN team
team.capacity::VARCHAR(64000) LIKE '$0'
The following query tries to subtract one number from another number, using SUBSTR
to extract the numbers from the ftscore
and htscore
. However, these columns are stored as character strings:
premdb=# \d match
Table "public.match"
Column | Type | Modifiers
----------+-----------------------------+-----------
seasonid | smallint |
matchday | timestamp without time zone |
htid | smallint |
atid | smallint |
ftscore | character(3) |
htscore | character(3) |
By default, an implicit cast to a TIMESTAMPTZ
is chosen and attempted for the SUBSTR
expression, but the query fails.
premdb=# select seasonid,htid,atid,ftscore,htscore,substr(ftscore,1,1)-substr(htscore,1,1) goaldiff
from match
where seasonid=22 and htid=2 and atid between 50 and 75
order by 1,2,3;
ERROR: invalid datetime format
DETAIL: [reason => invalid input syntax for type timestamp with time zone: "1"]
If one of the arguments in the expression is explicitly cast to an integer, the query succeeds:
premdb=# select seasonid,htid,atid,ftscore,htscore,
substr(ftscore,1,1)::smallint-substr(htscore,1,1) goaldiff
from match
where seasonid=22 and htid=2 and atid between 50 and 75
order by 1,2,3 ;
seasonid | htid | atid | ftscore | htscore | goaldiff
----------+------+------+---------+---------+----------
22 | 2 | 52 | 1-3 | 1-1 | 0
22 | 2 | 61 | 2-0 | 0-0 | 2
22 | 2 | 63 | 0-0 | 0-0 | 0
22 | 2 | 65 | 2-0 | 0-0 | 2
22 | 2 | 67 | 1-1 | 0-0 | 1
22 | 2 | 68 | 2-0 | 0-0 | 2
22 | 2 | 69 | 2-0 | 1-0 | 1
22 | 2 | 73 | 2-0 | 1-0 | 1
22 | 2 | 74 | 1-1 | 0-1 | 1
22 | 2 | 75 | 0-0 | 0-0 | 0
(10 rows)
Adding Two Character Strings
This example shows the expected behavior when both sides of an addition operator are character strings. The query returns an error because the expected calculation is ambiguous in this context:
premdb=# create table varnum(c1 char(5), c2 varchar(5));
CREATE TABLE
premdb=# insert into varnum values(1,1);
INSERT 0 1
premdb=# insert into varnum values(10,20);
INSERT 0 1
premdb=# select c1+c2 from varnum;
ERROR: operator is not unique: character + character varying
LINE 1: select c1+c2 from varnum;
^
HINT: Could not choose a best candidate operator. You might need to add explicit type casts.
Note that when you cast one side of the addition operator explicitly, the other side is implicitly cast to match that type. In the first example, column c2
is implicitly cast to an integer; in the second example, c2
is implicitly cast to an interval:
premdb=# select c1::int+c2 from varnum;
?column?
----------
2
30
(2 rows)
premdb=# select c1::interval+c2 from varnum;
?column?
----------
00:00:02
00:00:30
(2 rows)
MACADDR Cast to MACADDR8
Seven rows are inserted into the following table, and the MACADDR
values for column c1
are cast implicitly to MACADDR8
for insertion into column c2
.
premdb=# \d mac
Table "public.mac"
Column | Type | Modifiers
--------+----------+-----------
c1 | macaddr |
c2 | macaddr8 |
Distribution: Hash (c1)
premdb=# insert into mac
premdb-# values('08:00:2b:01:02:03', '08:00:2b:01:02:03'),
premdb-# ('08-00-2b-01-02-03', '08-00-2b-01-02-03'),
premdb-# ('08002b:010203', '08002b:010203'),
premdb-# ('08002b-010203', '08002b-010203'),
premdb-# ('0800.2b01.0203', '0800.2b01.0203'),
premdb-# ('0800-2b01-0203', '0800-2b01-0203'),
premdb-# ('08002b010203', '08002b010203');
INSERT 0 7
premdb=# select * from mac;
c1 | c2
-------------------+-------------------------
08:00:2b:01:02:03 | 08:00:2b:ff:fe:01:02:03
08:00:2b:01:02:03 | 08:00:2b:ff:fe:01:02:03
08:00:2b:01:02:03 | 08:00:2b:ff:fe:01:02:03
08:00:2b:01:02:03 | 08:00:2b:ff:fe:01:02:03
08:00:2b:01:02:03 | 08:00:2b:ff:fe:01:02:03
08:00:2b:01:02:03 | 08:00:2b:ff:fe:01:02:03
08:00:2b:01:02:03 | 08:00:2b:ff:fe:01:02:03
(7 rows)
IPV4 Cast to IPV6
The following example shows an IPV4
value cast to an IPV6
value for storage in an IPV6
column:
premdb=# select * from ipv4_ipv6;
c1 | c2
---------------+-----------------------------------------
19.120.51.251 | 684d:1111:0222:3333:4444:5555:0006:0077
(1 row)
premdb=# insert into ipv4_ipv6(c2) select c1 from ipv4_ipv6;
INSERT 0 1
premdb=# select * from ipv4_ipv6;
c1 | c2
---------------+-----------------------------------------
[NULL] | 0000:0000:0000:0000:0000:ffff:1378:33fb
19.120.51.251 | 684d:1111:0222:3333:4444:5555:0006:0077
(2 rows)
premdb=# explain (verbose) insert into ipv4_ipv6(c2) select c1 from ipv4_ipv6;
QUERY PLAN
-----------------------------------------------------------------------------------------
id rows_planned mem_planned mem_actual workers node
2 1 3.00Gi H 0.00 all INSERT INTO ipv4_ipv6
(NULL, ipv4_ipv6.c1::IPV6)
distribute on (NULL)
3 1 272.00Mi H 0.00 all DISTRIBUTE ON HASH(NULL)
(NULL, ipv4_ipv6.c1::IPV6)
distribute on (NULL) distribute on (ipv4_ipv6.c1)
...