Why do you only need double quotation marks in SQL for particular cases? - sql

I have a column in my database table named UID. For some reason queries fail unless I surround the column name with double quotation marks (" "). None of the other columns require these quotation marks.
For example, this doesn't work:
SELECT user_name FROM user_table WHERE UID = '...'
But this does:
SELECT user_name FROM user_table WHERE "UID" = '...'
Is UID some kind of keyword? Why is it only happening to that column? How do I know if I need to use double quotes for other columns?
By the way, I'm running JDK 1.8_221 and using an oracle JDBC driver if that makes a difference.

Yes, it is about keywords. You can double quote everything (tables, columns) to avoid this but I can understand you don't want to do this.
To have a list of standard keywords: SQL Keywords
But you can see UID is not in this list as I assume it is a reserved keyword by your database implementation. I had the same problem with a table called "order" as it contains orders. ORDER is a keyword so I had to quote it each time.
So best is to test your statements using a SQL client tool.
Since you mention Oracle: Oracle keywords: "You can obtain a list of keywords by querying the V$RESERVED_WORDS data dictionary view."

If your create table command for user_table looks something like this:
create table user_table ("UID" varchar2(10))
then you will have to use quotes around UID in your query. This query:
select * from user_table where UID = 'somestring'
means to use the Oracle predefined UID pseudo column and your table's UID column will not be accessed.
If your table doesn't have a user-defined UID column, then using "UID" should fail.
My guess is your table does indeed have a UID column and when you say it "doesn't work" without using the quotes you probably mean it motivates an ORA-1722.
The type of failure, when using UID without quotes, depends on the content of the string 'somestring'. If the content of that string can be cast as a number then you probably won't get the rows you expect. If it cannot be cast as a number then you'll get an ORA-1722.
As an aside, if you try to execute this, then you'll get an ORA-904:
create table user_table (UID number)

Yes, it is keywords and return
UID returns an integer that uniquely identifies the session user (the
user who logged on).
By default, Oracle identifiers (table names, column names, etc.) are case-insensitive. You can make them case-sensitive by using quotes around them when creating them (eg: SELECT * FROM "My_Table" WHERE "my_field" = 1). SQL keywords (SELECT, WHERE, JOIN, etc.) are always case-insensitive.
You can use it for more information here.

Related

Regex validation of table schema and name

I have an API that performs some query on a table that the caller specifies. The table name is placed in the query via string replace, and so is a risk for SQL injection.
Example:
tableName = req.body.tableName;
sql = "SELECT * FROM <<TABLE_NAME>>;";
sql = sql.replace("<<TABLE_NAME>>", tableName);
I'm required to keep this query dynamic, as we don't want to redeploy this code every time we add a new table. In other words, I can't just maintain a list of valid table names.
So for the purposes of keeping this safe from sql injection, is it sufficient to do a regex validation on the table name? We can be certain the table name will always be of the format schema.table_name where table_name will be only a-z, 0-9, -, _
Is there any sql injection that could slip past this table name regex?
^myschema\.[a-zA-Z0-9-_]+$
Since minus is not a valid character in a tablename, you could change your regex to just:
^myschema\.\w+$
\w is equivalent to [a-zA-Z0-9_]
There is no risk of injection.
Most databases allow special characters, even spaces and minuses, in table names if special syntax is used, eg
MySQL: `my stupid table-name!`
Postgres: "my stupid table-name!"
SQL Server: [my stupid table-name!]
It is poor practice to allow non-standard characters in names in the first place, and it would be fine to deny such names in your situation.
The minus sign cannot be used as an identifier in SQL. In the case of table names, I don't think it will lead to SQL injection attacks, but if you allow minus signs in column names, subtraction can be injected.
In the case of MySQL, the following SQL statement will return all users, not just 'tom'. This is because of the implicit type conversion that occurs when subtracting from a string.
SELECT * FROM users WHERE myschema.user-0 = 'tom'
The workaround is to exclude the minus sign or quote the identifier. The following will not result in a SQL injection attack.
SELECT * FROM users WHERE `myschema`.`user-0` = 'tom'.
The above is the way to write for MySQL, and the way to write for standard SQL is as follows
SELECT * FROM users WHERE "myschema"."user-0" = 'tom'

How to select value from Oracle table having field name as default keyword

We have Oracle table having default keyword(i.e in as field name) field name.Now i am querying table but unable to extract specific field data.
select a.filename,a.in from table a
Following error appears "invalid field name.
Try using double quotes.
select a."IN" from table a
You can use default (oracle reserved) keywords as the name of the columns but yes it is not advisable to use it.
Anyway, If you want to use oracle reserved keywords then you must have to enclose them in the double-quotes.
Note that oracle is case insensitive in terms of its object names until and unless it is wrapped in the double-quotes. it means if you enclose any object name in double-quotes then you must have to use them anywhere in the entire DB as case sensitive manner.
So if your table definition is:
CREATE TABLE YOUR_TABLE ("IN" NUMBER);
Then you need to use "IN" wherever you want to refer the column but if your table definition is:
CREATE TABLE YOUR_TABLE ("in" NUMBER);
Then you need to use "in" wherever you want to refer the column. -- case sensitive names.
I hope it will clear all your doubts.
Cheers!!

Asp Classic & Firbird Sql without quotation marks

I have a script in ASP Classic that uses a Firebird database. I would like to execute a query without "quotation marks"
Now I must write this:
SQL = "SELECT ""TArticoli"".""IDArticolo"",""TArticoli"".""Desc"" FROM ""TArticoli"";"
I would write this:
SQL = "SELECT TArticles.IDArticle, TArticles.Desc FROM TArticles;"
The first one is accepted the second not, how can I do this?
You can't. DESC is a reserved word in Firebird, so to be able to use it as a column name (or any other object name for that matter), you will need to enclose it in quotes.
A second problem is that you are currently using
SELECT "TArticoli"."IDArticolo","TArticoli"."Desc" FROM "TArticoli"
And this means both your table name and the column names are case sensitive, and in that case, quoting those object names is mandatory. Unquoted object names are case insensitive, but are mapped to object names in upper case. This means that select * from TArticoli will select from a table called TARTICOLI, while select * from "TArticoli", selects from a table called TArticoli.
So unless you are going to rename or recreate all your tables or columns, you will not be able to get rid of quotes. The only thing you can do to reduce the number of quotes, is by not prefixing the columns with the table names (in the query shown it isn't necessary), or otherwise use a case insensitive alias for the table, eg
SELECT "IDArticolo", "Desc" FROM "TArticoli"
or
SELECT a."IDArticolo", a."Desc" FROM "TArticoli" AS a

Oracle table column name with space

Is it possible to create a table with column name containing space? If so how can I create and use it?
It is possible, but it is not advisable. You need to enclose the column name in double quotes.
create table my_table ("MY COLUMN" number);
But note the warning in the documentation:
Note: Oracle does not recommend using quoted identifiers for database
object names. These quoted identifiers are accepted by SQL*Plus, but
they may not be valid when using other tools that manage database
objects.
The name will be case-sensitive, and you wil have to enclose the name in double quotes every time you reference it:
select "MY COLUMN" from my_table;
So... don't, would be my advice...
Yes, it's possible. You just have to be sure to quote the column name. For instance:
CREATE TABLE Fubar ("Foo Bar" INT);
INSERT INTO Fubar VALUES (1337);
SELECT "Foo Bar" FROM SpaceMonster
Even though it's possible, it doesn't make it a good idea. You'll probably save yourself from a lot of pain if just replace all you spaces with underscores.
it is possible by naming the column between two "
example: "My columN" , the column name becomes case sensitive which means.
SELECT "my column" from table; --NOT OK
SELECT "My columN" from table; --OK
You can (see the Oracle doc) if you quote these appropriately. However I suspect this is not a good idea, since you'll have to quote everything. Generally db naming standards / conventions (e.g. here or here) favour using underscores (which don't require quoting) over whitespace.
This is the columns rule defined for oracle
Columns (for tables)
All columns are in form {alias}_{colname}. For example prs_id,
prs_name, prs_adr_id, adr_street_name. This guarantees that column
names are unique in a schema, except denormalized columns from
another table, which are populated using triggers or application
logic.
All columns are in singular. If you think you need a column name in plural think twice whether it is the right design? Usually it
means you are including multiple values in the same column and that
should be avoided.
All tables have surrogate primary key column in form {alias}_id, which is the first column in the table. For example, prs_id, mat_id,
adr_id.
you can always have alias for column name bu using ""
Did you Google for this? I did - the 6th link was this, in which I find the following:
create table employee (
"First Name" varchar2(20),
"Last Name" varchar2(20),
Address varchar2(60),
Phone varchar2(15),
Salary number,
EmpID number,
DeptID number
);
... which works fine when I tried it in 10g.

SQL with LIMIT1 returns all records

I made a mistake and entered:
SELECT * FROM table LIMIT1
instead of
SELECT * FROM table LIMIT 1 (note the space between LIMIT and 1)
in the CLI of MySQL. I expected to receive some kind of parse error, but I was surprised, because the query returned all of the records in the table. My first thought was "stupid MySQL, I bet that this will return error in PostgreSQL", but PostgreSQL also returned all records. Then tested it with SQLite - with the same result.
After some digging, I realized that it doesn't matter what I enter after the table. As long as there are no WHERE/ORDER/GROUP clauses:
SELECT * FROM table SOMETHING -- works and returns all records in table
SELECT * FROM table WHERE true SOMETHING -- doesn't work - returns parse error
I guess that this is a standardized behavior, but I couldn't find any explanation why's that. Any ideas?
Your first query is equivalent to this query using a table alias:
SELECT * FROM yourtable AS LIMIT1
The AS keyword is optional. The table alias allows you to refer to columns of that table using the alias LIMIT1.foo rather than the original table name. It can be useful to use aliases if you wish to give tables a shorter or a more descriptive alias within a query. It is necessary to use aliases if you join a table to itself.
From the SQL lite documentation:
This is why I want DB engine to force the usage of keyword AS for alias names
http://beyondrelational.com/modules/2/blogs/70/posts/10814/should-alias-names-be-preceded-by-as.aspx
SELECT * FROM table LIMIT1;
LIMIT1 This has taken as alias by SQL, cause LIMIT1 is not a reserved literal of SQL.
Something after table name and that is not a reserved keyword always taken as an table alias by SQL.
SELECT * FROM table LIMIT 1;
When you used LIMIT just after the table name, SQL found that as a reserved keyword and worked for it as per the behavior. IF you want to use reserved key words in query It can be done by putting reserved literals in quotes. like..
SELECT * FROM table `LIMIT`;
OR
SELECT * FROM table `LIMIT 1`;
Now all words covered under `` quotes will treated as user defined.
Commonly we did mistake with date, timestamp, limit etc.. keywords by using them as column names.