Postgres: why do I need to quote column name in max()? [duplicate] - sql

This question already has answers here:
When do Postgres column or table names need quotes and when don't they?
(2 answers)
Omitting the double quote to do query on PostgreSQL
(5 answers)
PostgreSQL "Column does not exist" but it actually does
(6 answers)
Postgresql Column Not Found, But Shows in Describe
(1 answer)
sql statement error: "column .. does not exist"
(1 answer)
Closed 3 years ago.
So I encountered the following behaviour which surprised me. I first thought DateTime might be a postgres data type but what about BidOpen? Then there is the funny thing with the case of the column name in the error message. I almost feel this has to do with unquoted names being case insensitive. Why do I need to surround the column name in quotes for the query to work?
mydatabase=# select max("DateTime") from fx.candle;
max
---------------------
2019-04-26 20:59:00
(1 row)
mydatabase=# select max(DateTime) from fx.candle;
ERROR: column "datetime" does not exist
LINE 1: select max(DateTime) from fx.candle;
^
HINT: Perhaps you meant to reference the column "candle.DateTime".
mydatabase=# select max(BidOpen) from fx.candle;
ERROR: column "bidopen" does not exist
LINE 1: select max(BidOpen) from fx.candle;
^
HINT: Perhaps you meant to reference the column "candle.BidOpen".
mydatabase=# select max("BidOpen") from fx.candle;
max
---------
125.816
(1 row)
The schema looks like this:
mydatabase=# \d fx.candle;
Table "fx.candle"
Column | Type | Modifiers
-----------+-----------------------------+-----------------------------------------------------------------
id | integer | not null default nextval('fx.candle_id_seq'::regclass)
DateTime | timestamp without time zone |
BidOpen | double precision | not null
BidHigh | double precision | not null
BidLow | double precision | not null
BidClose | double precision | not null
AskOpen | double precision | not null
AskHigh | double precision | not null
AskLow | double precision | not null
AskClose | double precision | not null
symbol_id | integer |
Indexes:
"candle_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"candle_symbol_id_fkey" FOREIGN KEY (symbol_id) REFERENCES fx.symbol(id)

My understanding is that Postgres is not case sensitive regarding column and table names unless you actually create them using double quotes in the beginning. If that be the case, then you would need to forever refer to them using double quotes, to ensure that the proper case literal is being used.
So, to avoid your current situation, you should also avoid creating column/table names in a case sensitive manner.
Your create table should look something like this:
create table fx.candle (
id integer not null default nextval('fx.candle_id_seq'::regclass),
...
datetime timestamp without time zone -- NO quotes here; important!
...
)

Related

Getting column does not exist error in postgresql sql table [duplicate]

This question already has answers here:
Error: Column does not exist in postgresql for update [duplicate]
(1 answer)
postgres column "X" does not exist
(1 answer)
Closed 2 years ago.
I have an sql table that looks like this in postgresql called test.
date | data | source
------------+---------+------------------
2015-09-23 | 128 | aaamt
2015-09-24 | 0 | aaamtx2
.....
I type SELECT * FROM test where source="aaamt" but I get the following error,
ERROR: column "aaamt" does not exist
LINE 1: SELECT * FROM test where source = "aaamt";
Why am I getting this error and how to I fix it?
You need to use single quote instead of double quote
SELECT * FROM test where source = 'aaamt'
Double quotes indicate to Postgres that you are trying to specify an identifier such as a column or table name. Use single quotes for string literals, and your query should work:
SELECT *
FROM test
WHERE source = 'aaamt';
To be clear here, you current query is basically being interpreted as this:
SELECT *
FROM test
WHERE source = aaamt;
Here aaamt is being treated as a column name or maybe some other database identifier, but not as a string literal.

Extras zeroes getting appended during round to two decimal point in postgres

I am writing a postgres procedure. In that I want to round a floating point number to two decimal point and then insert that into a table. I have written the below code.
vara float8;
SELECT round( float8 '3.1415927', 2 ) into vara;
insert into dummyTable(columnA)values(vara).
I want the columnA to contain the value 3.14. However the value which is getting inserted is 3.1400.
The data type of columnA is float8 with precision and scale 17.
There is only one function round with two arguments, and that takes numeric as argument:
test=> \df round
List of functions
Schema | Name | Result data type | Argument data types | Type
------------+-------+------------------+---------------------+------
pg_catalog | round | double precision | double precision | func
pg_catalog | round | numeric | numeric | func
pg_catalog | round | numeric | numeric, integer | func
(3 rows)
So what happens is that your float8 is converted to numeric (without scale), and the result is of the same type. This will not produce trailing zeros:
test=> SELECT round(3.14159265, 2);
round
-------
3.14
(1 row)
But if you store the result in a float8 column, you may get rounding errors:
test=> SET extra_float_digits = 3;
SET
test=> SELECT round(3.14159265, 2)::float8;
round
---------------------
3.14000000000000012
(1 row)
My recommendation is to use numeric(10,2) or something similar as the data type of the table column, then the rounding will happen automatically, and the value can never have more than two decimal places.

How to do a count of fields in SQL with wrong datatype

I am trying to import legacy data from another system into our system. The problem I am having is that the legacy data is dirty- very dirty! We have a field which should be an integer, but sometimes is a varchar, and the field is defined as a varchar...
In SQL Server, how can I do a select to show those records where the data is varchar instead if int?
Thanks
If you want to find rows1 where a column contains any non-digit characters or is longer than 9 characters (either condition means that we cannot assume it would fit in an int, use something like:
SELECT * FROM Table WHERE LEN(ColumnName) > 9 or ColumnName LIKE '%[^0-9]%'
Not that there's a negative in the LIKE condition - we're trying to find a string that contains at least one non-digit character.
A more modern approach would be to use TRY_CAST or TRY_CONVERT. But note that a failed conversion returns NULL and NULL is perfectly valid for an int!
SELECT * FROM Table WHERE ColumnName is not null and try_cast(ColumnName as int) is null
ISNUMERIC isn't appropriate. It answers a question nobody has ever wanted to ask (IMO) - "Can this string be converted to any of the numeric data types (I don't care which ones and I don't want you to tell me which ones either)?"
ISNUMERIC('$,,,,,,,.') is 1. That should tell you all you need to know about this function.
1If you just want a count, as per the title of the question, then substitute COUNT(*) for *.
In SQL Server, how can I do a select to show those records where the data is varchar instead of int?
I would do it like
CREATE TABLE T
(
Data VARCHAR(50)
);
INSERT INTO T VALUES
('102'),
(NULL),
('11Blah'),
('5'),
('Unknown'),
('1ThinkPad123'),
('-11');
SELECT Data -- Per the title COUNT(Data)
FROM
(
SELECT Data,
cast('' as xml).value('sql:column("Data") cast as xs:int ?','int') Result
FROM T --You can add WHERE Data IS NOT NULL to exclude NULLs
) TT
WHERE Result IS NULL;
Returns:
+----+--------------+
| | Data |
+----+--------------+
| 1 | NULL |
| 2 | 11Blah |
| 3 | Unknown |
| 4 | 1ThinkPad123 |
+----+--------------+
That if you can't use TRY_CAST() function, if you are working on 2012+ version, I'll recommend that you use TRY_CAST() function like
SELECT Data
FROM T
WHERE Data IS NOT NULL
AND
TRY_CAST(Data AS INT) IS NULL;
Demo
Finally, I would say do not use ISNUMERIC() function because of (from docs) ...
Note
ISNUMERIC returns 1 for some characters that are not numbers, such as plus (+), minus (-), and valid currency symbols such as the dollar sign ($). For a complete list of currency symbols, see money and smallmoney (Transact-SQL).

How to extract a node in a Postgres record datatype

I am using Postgres 9.1 and I have a function that returns a record datatype using the row() function.
For a simple example, try:
select row(1,2,3);
It will return a single-cell row with "(1,2,3)" in it.
In my more complex function, it returns a geocode and other data as in:
(90,"Sydney, Australia",0.431951065304161,151.208784,-33.873982)
So what I am trying to do is figure out how to exact each of these node values in this "row" or "array" (whatever is technically correct).
Anybody that can help, this would be appreciated.
Example function:
create or replace function a_function()
returns record language sql as $$
select 90, 'Sydney, Australia'::text, 0.431951065304161, 151.208784, -33.873982;
$$;
select a_function();
a_function
------------------------------------------------------------------
(90,"Sydney, Australia",0.431951065304161,151.208784,-33.873982)
(1 row)
You should call the function in from clause with a column definition list:
select *
from a_function() as (id int, city text, num1 numeric, num2 numeric, num3 numeric);
id | city | num1 | num2 | num3
----+-------------------+-------------------+------------+------------
90 | Sydney, Australia | 0.431951065304161 | 151.208784 | -33.873982
(1 row)
I kept searching and I found the answer this doc:
http://www.tutorialspoint.com/postgresql/postgresql_data_types.htm
Look under "Accessing Composite Types".
Essentially the record array is an associative array (or key=>value pair).
You have to use the key name in order to pull it out of the array.

Finding MySQL errors from LOAD DATA INFILE

I am running a LOAD DATA INFILE command in MySQL and one of the files is showing errors at the mysql prompt.
How do I check the warnings and errors? Right now the only thing I have to go by is the fact that the prompt reports 65,535 warnings on import.
mysql> use dbname;
Database changed
mysql> LOAD DATA LOCAL INFILE '/dump.txt'
-> INTO TABLE table
-> (id, title, name, accuracy);
Query OK, 897306 rows affected, 65535 warnings (16.09 sec)
Records: 897306 Deleted: 0 Skipped: 0 Warnings: 0
How do I get mysql to show me what those warnings are? I looked in the error log but I couldn't find them. Running the "SHOW WARNINGS" command only returned 64 results which means that the remaining 65,000 warnings must be somewhere else.
2 |
| Warning | 1366 | Incorrect integer value: '' for column 'accuracy' at row 2038
3 |
| Warning | 1366 | Incorrect integer value: '' for column 'accuracy' at row 2038
4 |
| Warning | 1366 | Incorrect integer value: '' for column 'accuracy' at row 2038
6 |
| Warning | 1366 | Incorrect integer value: '' for column 'accuracy' at row 2038
7 |
+---------+------+--------------------------------------------------------------
--+
64 rows in set (0.00 sec)
How do I find these errors?
The MySQL SHOW WARNINGS command only shows you a subset of the warnings. You can change the limit of warning shown by modifying the parameter max_error_count.
Getting that many errors suggests that you have the wrong delimiter or extraneous quote marks that are making MySQL read the wrong columns from your input.
You can probably fix that by adding
[{FIELDS | COLUMNS}
[TERMINATED BY 'string']
[[OPTIONALLY] ENCLOSED BY 'char']
[ESCAPED BY 'char']
]
[LINES
[STARTING BY 'string']
[TERMINATED BY 'string']
]
after the tablename and before the column list.
Something like:
LOAD DATA LOCAL INFILE '/dump.txt'
INTO TABLE table
fields terminated by ' ' optionally enclosed by '"'
(id, title, name, accuracy);
By default, if you don't specify this, MySQL expects the tab character to terminate fields.
There could be a blank entry in the data file, and the target table doesn't allow null values, or doesn't have a valid default value for the field in question.
I'd check that the table has a default for accuracy - and if it doesn't, set it to zero and see if that clears up the errors.
Or you could pre-process the file with 'awk' or similar and ensure there is a valid numeric value for the accuracy field in all rows.