Oracle SELECT - Double quotes or no double quotes? [duplicate] - database

This question already has answers here:
Oracle SQL Syntax: Quoted identifier
(4 answers)
ORA-00904: invalid identifier
(13 answers)
Closed 9 years ago.
All,
When writing SELECT queries for Oracle 11i databases, why do some tables in Oracle enforce applying quotation marks to the fields being selected, and others not.
An example I've recently come across:
In Aqua Data Studio in a Query Analyzer window I have attempted to select the same field from two different tables:
select _id from table1
select _id from table2
table1 and table2 differ greatly, but Only table1 executes this select statement without an error. When I try to execute this statement for table2 I get the following:
ORA-00904: "_ID": invalid identifier
Script line 1, statement line 1, column 7
However, when I execute the second statement like this it works perfectly:
select "_id" from table2
Does anyone know what is going on here, why is this the case, and what could the key differences be between the tables be that is causing this?
Thanks

The answers and links about casing are correct, but your situation goes a little beyond a simple case issue, both because your column name started with an underscore and because your client is apaprently usually hiding the quoting from you.
If you tried to create a table with a column called _id, without quoting it, then you'd get an 'ORA-00911: invalid character' error, the cause text of which says 'identifiers may not start with any ASCII character other than letters and numbers'; which is actually wrong as well since it can't start with a number either (for example, 0_id gives 'ORA-00904: : invalid identifier'). This is backed up by the database object naming rules:
Nonquoted identifiers must begin with an alphabetic character from your database character set. Quoted identifiers can begin with any
character.
So it looks like Aqua Data Studio is following a convention of enclosing the upper-case version of the object name you supply in double-quotes, a practice mentioned in one of the linked posts.
From what you've shown, select _id from ... gets passed to Oracle as select "_ID" from ..., which is fine if the column name was created as "_ID". It appears that is the case for table1, but table2 was created as "_id" - so that case mismatch generates the legitimate ORA-00904 you're seeing.
Your client is not modifying a column name that is already enclosed in double-quotes, so select "_id" from ... is passed through to Oracle as-is, and works OK for table2 (but, conversely, would fail for table1).
Oracle requires the name to be enclosed in double quotes if it doesn't follow the rules for unquoted identifiers, and if it was created as quoted - unless the original quoted value was valid anyway, i.e. follows the unquoted rules and was entered in uppercase. Since your column name starts with an underscore, as far as Oracle is concerned all references to it have to be enclosed in double-quotes regardless of the case. Your client is just doing that in the background if you haven't quoted it yourself.
Following the advice others have given to avoid quoted identifiers and to always use names that are valid unquoted would avoid issues like this.

The problem comes from the creation of the object.
If you create an object with lower case AND quotation marks, it will enforce case sensitivity.
So you'll need to use quotation marks and right casing to use it.
If you create without quotes (or all in upper case), you won't face any "case sensitivity" problems, and will be able to select object with lower or upper case (without quotation marks)

Related

Unable to get where clause to work with text containing a single quotation

I am working with some geo-spatial (string) data that i have been saving into an SQL server database, whenever my data has had a single quote within the string i am saving, i have tried to escape this by padding the single quote. Though this allows me to save the text into my database, when i try to use a where clause to find locations which have been had an escape sequence applied to them, the where clause does not seem to pick them up.
For example
SELECT * from tb_test WHERE Address = 'Abbey Gardens, St John''s Wood, London, NW8';
Will produce an empty table, even if this record exists. The only want i have been able to get this to work was by using LIKE to match the pattern of my text which does not include the quotation (see below).
SELECT * from tb_test WHERE Address LIKE 'Abbey Gardens'
Is there any reason as to why SQL does not pick up on the full Address ? and if so how can i get it to?
SELECT * from tb_test WHERE Address = 'Abbey Gardens, St John''s Wood,
London, NW8'; Will produce an empty table, even if this record exists.
The quotes are proper in the literal so it seems the actual column value does not match the literal value. This could be due to trailing whitespace (e.g. tab, newline, etc.). Check the raw binary value of the column for unexpected characters:
SELECT CAST(Address AS varbinary(MAX)), *
FROM tb_test
WHERE Address LIKE 'Abbey Gardens%';

SQL would using between statement improve this?

I want to find out using a select statement what columns in a table share similar information.
Example: Classes table with ClassID, ClassName, ClassCode, ClassDescription columns.
This was part of my SQL class that I already turned in. The question asked "What classes are part of the English department?"
I used this Select statement:
SELECT *
FROM Classes
WHERE ClassName LIKE "English%" OR ClassCode LIKE "ENG%"
Granted we have only input one actual English course in this database, the end result was it executed fine and displayed everything for just the English class. Which I thought was a success since we did populate other non English courses in the database.
Anyways, I was told I should have used a BETWEEN statement.
I am just sitting here thinking they would both do what I needed them to do right?
I'm using SQL Server 2014
No, BETWEEN would probably be a bad idea here. BETWEEN doesn't allow wildcards and doesn't do any pattern matching in any RDBMS I've used. So you'd have to say BETWEEN 'ENG' AND 'English'. Except that doesn't return things like 'English I' (which would be after 'English' in a sorted list).
It would also potentially include something like 'Engineering' or 'Engaging Artistry', but that's a weakness of your existing query, too, since LIKE 'ENG%' matches those.
If you happen to be using a case-sensitive collation you add a whole new dimension of complexity. Your BETWEEN statement gets even more confusing. Just know that capital letters generally come before lower case letters, so 'ENGRAVING I' would be included but 'Engraving I' would not. Additionally, 'eng' would not be included. Note that case-insensitive collation is the default.
Also whats the difference when searching for null values in one table
and one column
column_name =''
or
column_name IS NULL
You're not understanding the difference between an empty string and null.
An empty string is explicit. It says "This field has a known value and it is a string of zero length."
A null string is imprecise. It means "unknown". It could mean "This value wasn't asked for," or "This value was not available," or "This value has not yet been determined," or "This values does not make sense for this record."
"What is this person's middle name?"
"He doesn't have one. See, his birth certificate has no middle name listed." --> Empty string
"I don't know. He never told me and I don't have any birth or identity record." --> NULL
Note that Oracle, due to backwards compatibility, treats empty strings as NULLs. This is explicitly against ANSI SQL, but since Oracle is that old and that's how it's always worked that's how it will continue to work.
Another way to look at it is the example I tend to use with numbers. The difference between 0 and NULL is the difference between having a bank account with $0 balance and not having a bank account at all.
Nothing can be said unless we see table and its data.Though don't use between.
Secondly first find which of the column is not null by design.Say for example ClassName cannot be null then there is no use using ClassCode LIKE "ENG%",just ClassName LIKE "English%" is enough,similarly vice versa is also true.
Thirdly you should use same parameter in both column.for example
ClassName LIKE "English%" OR ClassCode LIKE "English%"
see the difference.
Select * FROM Classes
Where ClassName LIKE "%English%"

Use of pipe symbol in Select clause

Is there any way/use of putting pipe symbol || in select clause.
I have come across following query in one of the article(probably to concatenate two values), but when I try to use the same in my query I am getting syntax error.
select FirstName ||''|| LastName As CustomerName from Customer
Please correct if I am using wrong syntax.
You can use CONCAT() function, which works in SQL Server 2012 and above, or just a plain + sign to do concatenation.
https://msdn.microsoft.com/en-us/library/hh231515(v=sql.110).aspx
Returns a string that is the result of concatenating two or more
string values.
you need to use '+' to perform Concat() instead of pipe if you are using SQL-Server. Pipe operator is not used in SQL-Server
It is used to concatenate you columns and output a single result i.e in one column.
For example, if i want to see first name and last name together as in one column then i could use pipes:
SELECT Fname||Lname FROM my_table;
If you are asking whether you can use pipes || for concatenation in Microsoft SQL, then the short answer is no.
If you’re asking about the concatenation operator itself, then read on.
|| is the standard ANSI concatenation operator. This is apparent in PostgreSQL, SQLite and Oracle, among others.
Microsoft, however uses +, because, why not. Except Microsoft Access uses &, because, why not.
MariaDB/MySQL have two modes. In traditional mode, || is interpreted as “or”, and there is no concatenation operator. In ANSI mode, || is interpreted as the concatenation operator.
Most DBMS (not SQLite) have the non-standard concat() function which will also concatenate. They also coalesce any NULLs to empty strings, so they’re a bit more forgiving if you don’t care about NULLs.

Is there any C SQLite API for quoting/escaping the name of a table?

It's impossible to sqlite3_bind_text a table name because sqlite3_prepare_v2 fails to prepare a statement such as:
SELECT * FROM ? ;
I presume the table name is needed to parse the statement, so the quoting needs to have happened before sqlite3_prepare_v2.
Is there something like a sqlite3_quote_tablename? Maybe it already exists under a name I can't recognize, but I can't find anything in the functions list.
SQLite will escape identifiers for you with the %w format in the https://www.sqlite.org/printf.html family of functions.
your proposed sqlite3_quote_tablename function could sanitize the input to prevent sql injection attacks. To do this it could parse the input to make sure it is a string literal. http://sqlite.org/lang_expr.html#litvalue
If a table name has invalid characters in it you can enclose the table name in double quotes, like this.
sqlite> create table "test table" (id);
sqlite> insert into "test table" values (1);
sqlite> select * from "test table";
id
----------
1
Of course you should avoid using invalid characters whenever possible. It complicates development and is almost always unnecessary (IMO the only time it is necessary is when you inherit a project that is already done this way and it's too big to change).
When using SQLite prepared statements with parameters the parameter: "specifies a placeholder in the expression for a literal value that is filled in at runtime"
Before executing any SQL statement, SQLite "compiles" the SQL string into a series of opcodes that are executed by an internal Virtual Machine. The table names and column names upon which the SQL statement operates are a necessary part of the compilation process.
You can use parameters to bind "values" to prepared statements like this:
SELECT * FROM FOO WHERE name=?;
And then call sqlite3_bind_text() to bind the string gavinbeatty to the already compiled statement. However, this architecture means that you cannot use parameters like this:
SELECT * FROM ? WHERE name=?; // Can't bind table name as a parameter
SELECT * FROM FOO WHERE ?=10; // Can't bind column name as a parameter
If SQLite doesn't accept table names as parameters, I don't think there is a solution for your problem...
Take into account that:
Parameters that are not assigned values using sqlite3_bind() are treated as NULL.
so in the case of your query, the table name would be NULL which of course is invalid.
I was looking for something like this too and couldn't find it either. In my case, the expected table names were always among a fixed set of tables (so those were easy to validate). The field names on the other hand weren't so I ended up filtering the string, pretty much removing everything that was not a letter, number, or underscore (I knew my fields would fit this parameters). That did the trick.

When naming columns in a SQL Server table, are there any names I should avoid using?

I remember when I was working with PHP several years back I could blow up my application by naming a MySQL column 'desc' or any other term that was used as an operator.
So, in general are there names I should avoid giving my table columns?
As long as you surround every column name with '[' and ']', it really doesn't matter what you use. Even a space works (try it: [ ]).
Edit: If you can't use '[' and ']' in every case, check the documentation for characters that are not allowable as well as keywords that are intrinsic to the system; those would be out of bounds. Off the top of my head, the characters allowed (for SqlServer) for an identifier are: a-z, A-Z, 0-9, _, $, #.
in general don't start with a number, don't use spaces, don't use reserved words and don't use non alphanumeric characters
however if you really want to you can still do it but you need to surround it with brackets
this will fail
create table 1abc (id int)
this will not fail
create table [1abc] (id int)
but now you need to use [] all the time, I would avoid names as the ones I mentioned above
Check the list of reserved keywords as indicated in other answers.
Also avoid using the "quoting" using quotes or square brackets for the sake of having a space or other special character in the object name. The reason is that when quoted the object name becomes case sensitive in some database engines (not sure about MSSQL though)
Some teams use the prefix for database objects (tables, views, columns) like T_PERSON, V_PERSON, C_NAME etc. I personally do not like this convention, but it does help avoiding keyword issues.
You should avoid any reserved SQL keywords (ex. SELECT) and from a best practices should avoid spaces.
Yes, and no.
Yes, because it's annoying and confusing to have names that match keywords, and that you have to escape in funny ways (when you're not consistently escaping)
and No, because it's possible to have any sequence of characters as an identifier, if you escape it properly :)
Use [square brackets] or "double quotes" to escape multi-word identifiers or keywords, or even names that have backslashes or any other slightly odd character, if you must.
Strictly speaking, there's nothing you can't name your columns. However, it will make your life easier if you avoid names with spaces, SQL reserved words, and reserved words in the language you're programming in.
You can use pretty much anything as long as you surround it with square brackets:
SELECT [value], [select], [insert] FROM SomeTable
I however like to avoid doing this, partly because typing square brackets everywhere is anoying and partyly because I dont generally find that column names like 'value' particularly descriptive! :-)
Just stay away from SQL keywords and anything which contains something other than letters and you shouldn't need to use those pesky square brackets.
You can surround a word in square brackets [] and basically use anything you'd like.
I prefer not to use the brackets, and in order to do so you just have to avoid reserved words.
MS SQL Server 2008 has these reserved words
Beware of using square brackets on updates, I had a problem using the following query:
UPDATE logs SET locked=1 WHERE [id] IN (SELECT [id] FROM ids)
This caused all records to be updated, however, this appears to work fine:
UPDATE logs SET locked=1 WHERE id IN (SELECT [id] FROM ids)
Note that this problem appears specific to updates, as the following returns only the rows expected (not all rows):
SELECT * FROM logs WHERE [id] IN (SELECT [id] FROM ids)
This was using MSDE 2000 SP3 and connecting to the database using MS SQL (2000) Query Analyzer V 8.00.194
Very odd, possibly related to this Knowledgebase bug http://support.microsoft.com/kb/140215
In the end I just removed all the unnecessary square brackets.

Resources