H2 table columns doesn't respect case when double-quoted - sql

I'm developing a tool which imports data into on-the-fly generated schema. Therefore I have little control over what the table or column names will look like. I recently run into an issue with creating 2 columns in the table which have identical name but different case. The problem could be demonstrated on this simplest DDL operation:
CREATE TABLE "a" (
"c1" integer,
"C1" integer
)
This fails for me in the program as well as h2 console with:
Duplicate column name "C1"; SQL statement: create table "a" ( "c1"
integer, "C1" integer )
This is working fine in PostgreSQL for example and I think it should work as the SQL specification requires case sensitivity when values are double-quoted.
I'm currently using in-memory h2 database.
EDIT: It runs out the reason was the connection was established with option DATABASE_TO_UPPER=false which caused this behaviour

In H2 Names are not case sensitive.
H2 docs
...but...
Quoted names are case sensitive, and can contain spaces.
H2 docs of Quoted Names
I just ran this exact example in a local instance of H2 and it worked fine.
create table p ("c1" integer, "C1" integer);
insert into p values (1,2);
select * from p;
I think your SQL is being changed before it runs in H2. Everything may be being capitalized before the SQL is run.
Per your update the connection was established with option DATABASE_TO_UPPER=false which caused this behaviour

Related

DBeaver adds single character when auto-completing a table name (for MariaDB databases at least)

DBeaver adds a character (the first letter of the table name) when auto completing table names, resulting in a query that looks like this:
select * from countries c;
As far as i can tell, it works, and has no impact on the query/results... can anyone enlighten me as to what it (the c) is?
"C" is an alias name of the "countries" table. Here is the reference: https://www.techonthenet.com/mariadb/alias.php

How can I create a calculate column in the creation of table in POSTGRESQL, for example in sql server LineTotal AS Price * Quantity [duplicate]

Does PostgreSQL support computed / calculated columns, like MS SQL Server? I can't find anything in the docs, but as this feature is included in many other DBMSs I thought I might be missing something.
Eg: http://msdn.microsoft.com/en-us/library/ms191250.aspx
Postgres 12 or newer
STORED generated columns are introduced with Postgres 12 - as defined in the SQL standard and implemented by some RDBMS including DB2, MySQL, and Oracle. Or the similar "computed columns" of SQL Server.
Trivial example:
CREATE TABLE tbl (
int1 int
, int2 int
, product bigint GENERATED ALWAYS AS (int1 * int2) STORED
);
fiddle
VIRTUAL generated columns may come with one of the next iterations. (Not in Postgres 15, yet).
Related:
Attribute notation for function call gives error
Postgres 11 or older
Up to Postgres 11 "generated columns" are not supported.
You can emulate VIRTUAL generated columns with a function using attribute notation (tbl.col) that looks and works much like a virtual generated column. That's a bit of a syntax oddity which exists in Postgres for historic reasons and happens to fit the case. This related answer has code examples:
Store common query as column?
The expression (looking like a column) is not included in a SELECT * FROM tbl, though. You always have to list it explicitly.
Can also be supported with a matching expression index - provided the function is IMMUTABLE. Like:
CREATE FUNCTION col(tbl) ... AS ... -- your computed expression here
CREATE INDEX ON tbl(col(tbl));
Alternatives
Alternatively, you can implement similar functionality with a VIEW, optionally coupled with expression indexes. Then SELECT * can include the generated column.
"Persisted" (STORED) computed columns can be implemented with triggers in a functionally equivalent way.
Materialized views are a related concept, implemented since Postgres 9.3.
In earlier versions one can manage MVs manually.
YES you can!! The solution should be easy, safe, and performant...
I'm new to postgresql, but it seems you can create computed columns by using an expression index, paired with a view (the view is optional, but makes makes life a bit easier).
Suppose my computation is md5(some_string_field), then I create the index as:
CREATE INDEX some_string_field_md5_index ON some_table(MD5(some_string_field));
Now, any queries that act on MD5(some_string_field) will use the index rather than computing it from scratch. For example:
SELECT MAX(some_field) FROM some_table GROUP BY MD5(some_string_field);
You can check this with explain.
However at this point you are relying on users of the table knowing exactly how to construct the column. To make life easier, you can create a VIEW onto an augmented version of the original table, adding in the computed value as a new column:
CREATE VIEW some_table_augmented AS
SELECT *, MD5(some_string_field) as some_string_field_md5 from some_table;
Now any queries using some_table_augmented will be able to use some_string_field_md5 without worrying about how it works..they just get good performance. The view doesn't copy any data from the original table, so it is good memory-wise as well as performance-wise. Note however that you can't update/insert into a view, only into the source table, but if you really want, I believe you can redirect inserts and updates to the source table using rules (I could be wrong on that last point as I've never tried it myself).
Edit: it seems if the query involves competing indices, the planner engine may sometimes not use the expression-index at all. The choice seems to be data dependant.
One way to do this is with a trigger!
CREATE TABLE computed(
one SERIAL,
two INT NOT NULL
);
CREATE OR REPLACE FUNCTION computed_two_trg()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
AS $BODY$
BEGIN
NEW.two = NEW.one * 2;
RETURN NEW;
END
$BODY$;
CREATE TRIGGER computed_500
BEFORE INSERT OR UPDATE
ON computed
FOR EACH ROW
EXECUTE PROCEDURE computed_two_trg();
The trigger is fired before the row is updated or inserted. It changes the field that we want to compute of NEW record and then it returns that record.
PostgreSQL 12 supports generated columns:
PostgreSQL 12 Beta 1 Released!
Generated Columns
PostgreSQL 12 allows the creation of generated columns that compute their values with an expression using the contents of other columns. This feature provides stored generated columns, which are computed on inserts and updates and are saved on disk. Virtual generated columns, which are computed only when a column is read as part of a query, are not implemented yet.
Generated Columns
A generated column is a special column that is always computed from other columns. Thus, it is for columns what a view is for tables.
CREATE TABLE people (
...,
height_cm numeric,
height_in numeric GENERATED ALWAYS AS (height_cm * 2.54) STORED
);
db<>fiddle demo
Well, not sure if this is what You mean but Posgres normally support "dummy" ETL syntax.
I created one empty column in table and then needed to fill it by calculated records depending on values in row.
UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
It is so dummy I suspect it is not what You are looking for.
Obviously it is not dynamic, you run it once. But no obstacle to get it into trigger.
Example on creating an empty virtual column
,(SELECT *
From (values (''))
A("virtual_col"))
Example on creating two virtual columns with values
SELECT *
From (values (45,'Completed')
, (1,'In Progress')
, (1,'Waiting')
, (1,'Loading')
) A("Count","Status")
order by "Count" desc
I have a code that works and use the term calculated, I'm not on postgresSQL pure tho we run on PADB
here is how it's used
create table some_table as
select category,
txn_type,
indiv_id,
accum_trip_flag,
max(first_true_origin) as true_origin,
max(first_true_dest ) as true_destination,
max(id) as id,
count(id) as tkts_cnt,
(case when calculated tkts_cnt=1 then 1 else 0 end) as one_way
from some_rando_table
group by 1,2,3,4 ;
A lightweight solution with Check constraint:
CREATE TABLE example (
discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);

Column or global variable not found

The issue is when querying a table created using Aqua Data Studio in our IBM DB2 database, column names can't be specified unless I use the system name. Tables made a short time ago don't have this issue. The query can find the column names just fine in them. There also is not a problem using wildcards and the column names display just fine.
For clarity:
this works : SELECT * FROM WUNITS.DVIRS
this works : SELECT ID___00001 FROM WUNITS.DVIRS
This doesn't : SELECT Id FROM WUNITS.DVIRS
This does work for older tables created the same way : SELECT Id FROM WUNITS.DVIRS
Here is a screenshot of the column definitions
What am I doing wrong?
Since you mention system name, I'll assume you're using Db2 for IBM i....
I suspect you've created the table with quoted column names...you wouldn't see mixed case column names otherwise, they would be all CAPITALS.
For example:
create table dtcwilt.dvirs (
"Id" bigint
, "AssetNumber" varchar(25)
, WoNumber bigint
, WoStatusId int
)
Not sure what tool you're using to display the columns, but the ACS schema tool would show the quoted name.
The quotes are actually part of the name, you'd need to use the quoted name, with proper capitalization, in your select:
This should work:
SELECT "Id" FROM WUNITS.DVIRS
This would not:
SELECT "ID" FROM WUNITS.DVIRS

Why does Oracle 12c query require double quotes around table [duplicate]

This question already has an answer here:
ORA-00942: table or view does not exist - Oracle
(1 answer)
Closed 7 years ago.
The database I'm querying is Oracle 12c. Detailed info about database version is as follows:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
I'm trying to eliminate the need to have double quotes around every view or table in my SQL query.
Following works (from Oracle Sql Developer GUI)
select m."Metadata"
from "EvMetadata" m
Following gives error (from Oracle Sql Developer GUI)
select m.Metadata
from EvMetadata m
Error is
ORA-00942: table or view does not exist
00942. 00000 - "table or view does not exist"
*Cause:
*Action: Error at Line: 2 Column: 6
I generated DDL, which looks like this
CREATE TABLE "EVP"."EvMetadata"
("EvMetadataId" NUMBER(10,0) GENERATED ALWAYS AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE ,
"InsertDate" TIMESTAMP (6),
"SessionId" NVARCHAR2(17),
"FileCheckSum" NVARCHAR2(32),
"Metadata" NCLOB,
"Device" NVARCHAR2(20),
"User" NVARCHAR2(20)
) SEGMENT CREATION IMMEDIATE
So based on #toddlermenot's comment below, it is very possible that this is how the table was created - with double quotes. I used ORM Entity Framework Code First to generate the schema for me so it seems like the ORM puts the double quotes by default.
Maybe you created the table with double quotes?
Using double quotes would preserve the case and since the table name has both upper and lower case letters in your example, Oracle is able to find it only when you use the double quotes.
Without the double quotes, Oracle probably uses a single case (upper?) irrespective of any case you might have in the table, by default.
For example:
if you create the table using
create table "TaBlE_NaMe" (blah..)
then you must use the double quotes in your SELECT.
If you create the table using
create table TaBlE_NaMe (blah..)
The SELECT without quote should work correctly. (It would work with the quote also if you had all the letters of the table's name in upper case)
Names in oracle be it table, column, object, view, package, procedure, function, etc. are by default UPPER CASE unless quoted with double quotes. Furthermore, all name resolution in oracle is case sensitive.
What this means is that when you create or attempt to use a database object without quoting the name oracle will implicitly convert that name to upper case before creating the object or resolving the name. So the unquoted EvMetadata table name is equivalent to the quoted upercase "EVMETADATA" table name but not to the quoted mixed case "EvMetadata" table name.

"Column not found" when selecting from a table in a different schema

I'm experiencing a very weird issue with H2.
In addition to all the tables residing in default ("PUBLIC") schema, I have several tables created in a separate schema (there's a valid business reason to do it that way, but it's irrelevant here). When I run
select * from schema1.table1
everything works perfectly. If I try to do the same but mention the column name(s) explicitly, e.g.
select col1, col2 from schema1.table1
the query fails with "Column col1 not found; 42S22/42122" error. This occurs whenever the column is referenced anywhere in select (from clause / where clause / etc...).
Column names are correct and they show up in INFORMATION_SCHEMA. Furthermore, if I quote them, query works properly - however this has a side effect of making column names case sensitive which then fails in Hibernate which apparently uppercases them anyway.
Am I overlooking something obvious here? Is there a reason for this bizarre behavior or is this a bug?
Update: Thomas's answer made me realize that the issue was not with a different schema but rather with how tables in that schema were created; specifically the use of quoted identifiers. Here's a script that reproduces the problem in H2 1.3.161 (latest version atm):
create table table1(col1 int, "col2" int);
insert into table1 values(1, 1);
select * from table1; -- works
select col1 from table1; -- works
select "col2" from table1; -- works
select col2 from table1; -- fails
I don't understand why there's a difference between the last 2 queries. Column name is case-sensitive here (because it was defined via quoted identifier), but it does have the correct case. INFORMATION_SCHEMA.COLUMNS shows no differences (aside from name) between the two columns either. Is case insensivity for unquoted columns obtained by forcibly uppercasing all queries?
The above script works as expected (as in all queries complete successfully) in Postgres.
I can't reproduce the problem. Could you post a complete, reproducible problem? I ran the following script in the H2 Console, and it works (meaning, I get no exception):
drop all objects;
create schema schema1;
create table schema1.table1(col1 int, col2 int);
insert into schema1.table1 values(1, 1);
select * from schema1.table1;
select col1, col2 from schema1.table1;
I had the same problem but in my case I was incorrectly using " instead of ' in the query