Hi I have a table that with integer data type and have values like "1000" ,"10000" "1000000" and I want to convert them as "1.000" , "10.000" and "1.000.000". Also I want to keep them in integer format. Is that possible ?
No you cannot store an integer that way:
show lc_numeric;
en_US.UTF-8
select 10,000::integer;
?column? | int4
----------+------
10 | 0
select 10.000::integer;
int4
------
10
select to_char(10000, '99G999');
to_char
---------
10,000
select to_number('10,000', '99G999');
to_number
-----------
1000
set lc_numeric='de_DE.UTF-8';
SET
show lc_numeric ;
lc_numeric
-------------
de_DE.UTF-8
select 10,000::integer;
?column? | int4
----------+------
10 | 0
(1 row)
select 10.000::integer;
int4
------
10
(1 row)
select to_char(10000, '99G999');
to_char
---------
10.000
select to_number('10.000', '99G999');
to_number
-----------
10000
lc_numeric:
lc_numeric (string)
Sets the locale to use for formatting numbers, for example with the to_char family of functions. Acceptable values are system-dependent; see Section 24.1 for more information. If this variable is set to the empty string (which is the default) then the value is inherited from the execution environment of the server in a system-dependent way.
So the only way locale specific information is going to be relevant is when you format the number to a string or vice versa.
Related
I have the following code :
start transaction;
show datestyle;
set datestyle to DMY;
show datestyle;
select
concat(timestamp_field, '')
from
my_table
;
commit;
It outputs this :
DateStyle
-----------
ISO, DMY
(1 ligne)
DateStyle (after set datestyle to DMY;)
-----------
ISO, DMY
(1 ligne)
select
concat(timestamp_field, '')
from
my_table
;
concat
---------------------
2004-09-01 00:00:00
(1 lignes)
My datestyle change doesn't seem to be accepted. Moreover, concat keeps using ISO to format my timestamp_field. I would expect something like this :
concat
---------------------
01/09/2004 00:00:00
(1 lignes)
NOTA: I don't want to use to_char function here. I want to understand how concat automagically convert a timestamp field.
In postgres I am trying to extract the name from pg_timezone_names() (https://www.postgresql.org/docs/8.2/static/view-pg-timezone-names.html). Right now, it is returning all the records in 1 column.
The version of Postgres is 8.0.2, and the below image is what select pg_timezone_names() returns:
After spinning my wheels on this for quite some time, I figured out how to make this work on Redshift (which is based off an old version of Postgres).
When you use just select pg_timezone_names() it returns a composite row record:
> select top 5 pg_timezone_names()
pg_timezone_names
------------------------------------------
(Antarctica/Macquarie,+11,11:00:00,f)
(Antarctica/McMurdo,NZST,12:00:00,f)
(Antarctica/Davis,+07,07:00:00,f)
(Antarctica/Rothera,-03,-03:00:00,f)
(Antarctica/DumontDUrville,+10,10:00:00,f)
However, we need to break down the composite record into separate columns before we can make use of them individually. This can be done like so:
> select top 5
tz.name,
tz.abbrev,
tz.utc_offset,
tz.is_dst
from pg_timezone_names() tz(name text, abbrev text, utc_offset interval, is_dst boolean);
name | abbrev | utc_offset | is_dst
--------------------------+--------+------------+-------
Antarctica/Macquarie | +11 | 11:00:00 | false
Antarctica/McMurdo | NZST | 12:00:00 | false
Antarctica/Davis | +07 | 07:00:00 | false
Antarctica/Rothera | -03 | -03:00:00 | false
Antarctica/DumontDUrville | +10 | 10:00:00 | false
Atleast on Postgres 10+, there is a pg_timezone_names view that can be used for this.
Simply use either of the below queries:
select * from pg_timezone_names;
or
select name from pg_timezone_names
t=# \sf pg_timezone_names()
CREATE OR REPLACE FUNCTION pg_catalog.pg_timezone_names(OUT name text, OUT abbrev text, OUT utc_offset interval, OUT is_dst boolean)
RETURNS SETOF record
LANGUAGE internal
STABLE PARALLEL SAFE STRICT
AS $function$pg_timezone_names$function$
so pg_timezone_names() is a function that returns a SETOF. This is why you see the whole row as one column, try:
select * from pg_timezone_names()
or in case of super old version maybe:
select * from pg_timezone_names() as t(name,abbrev,utc_offset,is_dest)
I am trying to create a manual table based off of a currently built views table.
The structure of this current table is as follows:
ID | Column1 | Column2 | Buffer Days
1 | Asdf | Asdf1 | 91
2 | Qwert | Qwert1 | 11
3 | Zxcv | Zxcv1 | 28
The goal is to add a 4th column after Buffer Days that lists the sys date + the number in buffer days
So the outcome would look like:
ID | Column1 | Column2 | Buffer Days | Lookout Date
1 | Asdf | Asdf1 | 91 | 02-Jan-18
That requirement smells like a virtual column candidate. However, it won't work:
SQL> create table test
2 (id number,
3 column1 varchar2(10),
4 buffer_days number,
5 --
6 lookout_date as (SYSDATE + buffer_days) --> virtual column
7 );
lookout_date as (SYSDATE + buffer_days)
*
ERROR at line 6:
ORA-54002: only pure functions can be specified in a virtual column expression
Obviously, as SYSDATE is a non-deterministic function (doesn't return the same value when invoked).
Why not an "ordinary" column in existing table? Because you shouldn't store values that are calculated using other table columns anyway. For example, good old Scott's EMP table contains SAL and COMM columns. It doesn't (and shouldn't) contain TOTAL_SAL column (as SAL + COMM) because - when SAL and/or COMM changes, you have to remember to update TOTAL as well.
Therefore, a view is what could help here. For example:
SQL> create table test
2 (id number,
3 column1 varchar2(10),
4 buffer_days number
5 );
Table created.
SQL> create or replace view v_test as
2 select id,
3 column1,
4 buffer_days,
5 sysdate + buffer_days lookout_date
6 from test;
View created.
SQL> insert into test (id, column1, buffer_days) values (1, 'asdf', 5);
1 row created.
SQL> select sysdate, v.* from v_test v;
SYSDATE ID COLUMN1 BUFFER_DAYS LOOKOUT_DA
---------- ---------- ---------- ----------- ----------
23.12.2017 1 asdf 5 28.12.2017
SQL>
I'm tying to convert timestamp field in format (YYYY-MM-DD HH:MI:SS.MS) to it's text representation. But for some reason getting different results:
If I'm trying to convert timestamp from table:
create table test_dt (dt timestamp);
insert into test_dt values ('2016-04-14 17:10:33.007');
insert into test_dt values ('2016-04-14 17:10:33');
Timestamps are getting truncated up to the seconds:
select dt::text from test_dt;
dt
---------------------
2016-04-14 17:10:33
2016-04-14 17:10:33
(2 rows)
But if Im using direct select statement, everything works:
select '2016-04-14 17:10:33.007'::timestamp::text;
varchar
-------------------------
2016-04-14 17:10:33.007
(1 row)
The question is not how to convert it to the text from table and include precision, but rather:
what am I doing wrong?
why those 2 approaches returns different result?
what's the rational behind this behaviour?
UPDATE
as #muistooshort suggested the following command gives the correct result:
select c::text from (select '2016-04-14 17:10:33.007'::timestamp union select '2016-04-14 17:10:33'::timestamp ) as t(c);
c
-------------------------
2016-04-14 17:10:33
2016-04-14 17:10:33.007
(2 rows)
and yes test_dt does have .007 :
select * from test_dt;
dt
-------------------------
2016-04-14 17:10:33
2016-04-14 17:10:33.007
(2 rows)
Also to_char gives milliseconds from the table:
select to_char(dt, 'YYYY-MM-DD HH:MI:SS.MS') from test_dt;
to_char
-------------------------
2016-04-14 05:10:33.000
2016-04-14 05:10:33.007
(2 rows)
I have table with columns of time(0) datatypes:
Name TimeOne TimeTwo TimeThree
------ ---------------- ---------------- ----------------
Sarah 06:45:00 03:30:00 NULL
John 06:45:00 NULL NULL
How to make SELECT statement so that the "CalculatedTotal" column is total from TimeOne, TimeTwo and TimeThree per row?
What I'd like to have is select query like this:
SELECT
Name,
TimeOne,
TimeTwo,
TimeThree,
TimeOne + TimeTwo + TimeThree As CalculatedTotal
FROM
MyTable
I'd like to get back resultset like this:
Name TimeOne TimeTwo TimeThree CalculatedTotal
------ ---------------- ---------------- ---------------- ---------------
Sarah 06:45:00 03:30:00 NULL 10:15:00
John 06:45:00 NULL NULL 06:45:00
Just using plus operator in select statement gives you an error:
Operand data type time is invalid for add operator.
You could determine the number of seconds for each time value, add them together and convert back to time:
select TimeOne, TimeTwo, TimeThree,
cast(dateadd(s, isnull(datediff(s, 0, TimeOne), 0) + isnull(datediff(s, 0, TimeTwo), 0) + isnull(datediff(s, 0, TimeThree), 0), 0) as time(0)) as CalculatedTotal
from MyTable
Try the below script.
select convert(time, CONVERT(datetime, '00:08:00.000') + CONVERT(datetime, '00:07:00.000'))
select convert(time,cast('00:08:00.000'as datetime)+cast('00:07:00.000' as datetime) ) as 'T'
I belive you can use the SUM() function
SELECT
Name,
TimeOne,
TimeTwo,
TimeThree,
SUM(TimeOne+TimeTwo+TimeThree) As CalculatedTotal
FROM
MyTable
But equally you might need to convert each to seconds first using the SECOND() function, then use SEC_TO_TIME() on the result.
Edit: I've just had a look at the manual:
The SUM() and AVG() aggregate functions do not work with temporal
values. (They convert the values to numbers, which loses the part
after the first nonnumeric character.) To work around this problem,
you can convert to numeric units, perform the aggregate operation, and
convert back to a temporal value. Examples:
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(time_col))) FROM tbl_name;
SELECT FROM_DAYS(SUM(TO_DAYS(date_col))) FROM tbl_name;