FROM clause in SQL Server - sql

There is a function in SQL server - TRIM
For example TRIM(',' FROM #str)
Documentation says - TRIM removes the space character char(32) or other specified characters from the start and end of a string.
But how does this function implemented in terms of sql? Why does FROM allowed there?
Official docs says that
In Transact-SQL, the FROM clause is available on the following statements:
DELETE
UPDATE
SELECT.
But I don't see select, update or delete here. How does it works? How can I implement similar function? Where is documentation for this feature at all?

This use of FROM has nothing to do with the FROM clause in a SELECT (or UPDATE or DELETE) statement.
It is simply the syntax for this particular function call. I think this form of the function is specified by the SQL standard.
Another case of such ambiguity -- that I can readily think of -- is GROUPING which is used for both GROUPING SETS and as a special function. There are probably others as well.

Related

TIMESTAMP_FORMAT not working with OFFSET in DB2

I'm trying to do pagination in DB2. I wouldn't like to do it with subquery, but OFFSET is not working with TIMESTAMP_FORMAT.
Use of function TIMESTAMP_FORMAT in QSYS2 not valid. Data mapping error on member
I've found this question, but seems here the problem is with content of column and it's not my case, as values are alright and TIMESTAMP_FORMAT works without OFFSET.
I didn't look for some other way to not use TIMESTAMP_FORMAT, as I need to create pagination on queries written not by me, but by client.
The query looks like this.
SELECT DATE(TIMESTAMP_FORMAT(CHAR("tablename"."date"),'YYMMDD'))
FROM tableName
OFFSET 10 ROWS
I get
"[SQL0583] Use of function TIMESTAMP_FORMAT in QSYS2 not valid."
I'm not sure how OFFSET can relate to TIMESTAMP_FORMAT, but when I replace the select with select * it works fine.
I wonder why there is a conflict between OFFSET and TIMESTAMP_FORMAT and is there a way to bypass this without subquery.
From Listing of SQL Messages:
SQL0583
Function &1 in &2 cannot be invoked where specified because it is
defined to be not deterministic or contains an external action.
Functions that are not deterministic cannot be specified in a GROUP BY
clause or in a JOIN clause, or in the default clause for a global
variable.
Functions that are not deterministic or contain an external
action cannot be specified in a PARTITION BY clause or an ORDER BY
clause for an OLAP function and cannot be specified in the select list
of a query that contains an OFFSET clause.
The RAISE_ERROR function
cannot be specified in a GROUP BY or HAVING clause.
I don't know how to check these properties for the QSYS2.TIMESTAMP_FORMAT function (there is no its definition in the QSYS2.SYSROUTINES table), but it looks like improper definition of this function - there is no reason to create it as not deterministic or external action.
You can "deceive" DB2 like this:
CREATE FUNCTION MYSCHEMA.TIMESTAMP_FORMAT(str VARCHAR(4000), fmt VARCHAR(128))
RETURNS TIMESTAMP
DETERMINISTIC
CONTAINS SQL
NO EXTERNAL ACTION
RETURN QSYS2.TIMESTAMP_FORMAT(str, fmt);
SELECT
DATE(MYSCHEMA.TIMESTAMP_FORMAT(CHAR(tablename.date), 'YYMMDD'))
--DATE(QSYS2.TIMESTAMP_FORMAT(CHAR(tablename.date), 'YYMMDD'))
FROM table(values '190412') tableName(date)
OFFSET 10 ROWS;
And use this function instead. It works on my 7.3 at least.
It's a harmless deception, and you may ask IBM support to clarify such a "feature" of QSYS2.TIMESTAMP_FORMAT...
I suspect your problem is bad data...
The default for the IBM interactive tools, STRSQL and ACS Run SQL Scripts, is OPTIMIZE(*FIRSTIO) meaning get the first few rows back as quickly as possible...
With the OFFSET 10 clause you're probably accessing rows initially that you didn't before.
Try the following
create table mytest as (
SELECT DATE(TIMESTAMP_FORMAT(CHAR("tablename"."date"),'YYMMDD')) as mydate
FROM tableName
) with data
If that doesn't error, then yes you've found a bug, open a PMR.
Otherwise, you can see how far along the DB got by looking at the rows in the new table and track down the record with bad data.

Informatica Coding to SQL

I am attempting to translate the following Informatica code to the equivalent SQL scripts. I am a little stuck as I am not familiar with Informatica and would appreciate any assistance.
The original informatica code reads as follows:
LTRIM(RTRIM(SUBSTR(COV_REINS_CONCAT_BK,11, INSTR(COV_REINS_CONCAT_BK, '|',1,3)-INSTR(COV_REINS_CONCAT_BK, '|',1,2)-1 ))) || 'C'
select LTRIM(RTRIM(SUBSTR(COV_REINS_CONCAT_BK,11,INSTR(COV_REINS_CONCAT_BK,'|',1‌​,3)
-INSTR(COV_REINS_CONCAT_BK,'|',1,2)-1 )))||'C' from TABLE;
Above script will work fine in Oracle. Please replace table with your table name.
It becomes increasingly difficult to port such expressions that make extensive use of INSTR function using the occurrence parameter.
Maybe it's easier to create in your MS-SQL database an INSTR equivalent function that supports the occurrence parameter. See how to create the dbo.INSTR function here.
On this same site you can also see a table with more function equivalences from Oracle to MS-SQL.
Then the expression from the comment becomes much easier to translate:
LTRIM(RTRIM(SUBSTRING(COV_REINS_CONCAT_BK,11,dbo.INSTR(COV_REINS_CONCAT_BK,'|',1‌​,3)
-dbo.INSTR(COV_REINS_CONCAT_BK,'|',1,2)-1 )))+'C'
Here SUBSTR became SUBSTRING, and INSTR became dbo.INSTR and concatenation || was changed to +.
The SUBSTR() and instr() functions are from the Informatica Transformation Language. IMHO it has its roots in function names from Oracle and MSSQL / Sybase function names. This is why it doesn't translate directly to either but is similar. The functions are very well documented in the online help. You'll need to review the switches in the INSTR() function for case sensitivity and the like to ensure their parallel can be written correctly in another tool. The numbers may translate to different things and in some of the Informatica functions the end arguments can be omitted such as, in the SUBSTR() function, meaning that the SUBSTR() will take effect from the numbered position to the end of the string regardless of length. The typing of the port in Informatica can affect the result too, although in this case, the combined function is performing a trim at the end.
SUBSTR() and INSTR() functions are not MS SQL Server functions. I'm guessing the code snippet is Oracle's PL/SQL. Try resources such as http://www.dba-oracle.com/oracle_news/2005_12_16_sql_syntax_differences.htm

Dynamically building WHERE clauses in SQL statements

I have a question regarding SQL. I have the following SQL statement:
SELECT id, First, Last, E_Mail, Notes
FROM mytable
WHERE SOMETHING_SHOULD_BE_HERE IS NOT NULL;
I know that the SOMETHING_SHOULD_BE_HERE should be a column(attribute) in my table. Is their a way I can put a variable that can refer to the column I'm trying to access? In my case their are 30 columns. Can I have a string for SOMETHING_SHOULD_BE_HERE that can be assigned in my program to the column in which I want to search?
Thanks
No. Variables in SQL can refer to data, but not to object names (columns, functions or other database objects).
If you are building the SQL query, you'll need to use string operations to build your query.
The column can't be variable, but the value of the column can. The parser needs to know what to bind to.
If you elaborate on what you're trying to solve and which platform you're using it would allow for more complete answers.
You can have different SQLs queries in your code and use each one according to the case.
Another way is generate dynamically the query according the fields you want.
Without dynamic SQL, this is probably your best bet:
SELECT
id, first, last, email, notes
FROM
My_Table
WHERE
CASE #column_name_variable
WHEN 'column_1' THEN column_1
WHEN 'column_2' THEN column_2
...
ELSE 'not null'
END IS NOT NULL
There might be some issues with data type conversions, so you might need to explicitly cast all of the columns to one data type (VARCHAR is probably the best bet). Also, there's a good chance that performance will be horrendous on this query. I'd test it thoroughly before even thinking about implementing something like this.
I mentioned this in my comment, but for completeness I'll put it here too... you can probably also accomplish this with dynamic SQL, but how you do that will depend on your database server (MS SQL Server, Oracle, mySQL, etc.) and there are usually some caveats to using dynamic SQL.
In JDBC program, yes,the select statement can be composed like string operation.
for(String colName: colList)
{
String sql="Select id, First, Last, E_Mail, Notes From mytable where "+colName+" IS NOT NULL";
//execute the sql statement
}
It depends on how you are going to find out the value of SOMETHING_SHOULD_BE_HERE.
If you are in an Oracle PLS/SQL environment you could build up the WHERE clause using dynamic SQL and then use EXECUTE IMMEDIATE to execute it.
If you have a small set number of possibilities you could use CASE to workaround your problem possibly.
Your question is unclear.
However I am quite sure that what you have in mind is the so-called dynamic SQL (and related). "Dynamic SQL" allows you to dynamically build and submit queries at runtime. However such functionalities may not exist for your RDBMS.
There are several ways to do this.
When your query would return one and only one row
then you have to consider the EXECUTE IMMEDIATE statements (along with sp_executesql in tSQL : http://msdn.microsoft.com/en-us/library/ms188001.aspx ; or the USING clause in PL/SQL : http://docs.oracle.com/cd/B14117_01/appdev.101/b10807/13_elems017.htm to specify a list of input/output bind arguments) and/or PREPARED statements (http://rpbouman.blogspot.fr/2005/11/mysql-5-prepared-statement-syntax-and.html).
When your query can return more than one row
then you have to consider techniques such as the EXECUTE IMMEDIATE statement with the BULK COLLECT INTO clause or the OPEN-FOR, FETCH, and CLOSE statements (explicit cursors in PL/SQL :
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/dynamic.htm)
Please note that except in some particular cases, most conventional techniques like IF-THEN-ELSE and CASE statements should be preferred (along with a good algorithm). Furthermore they work with almost all RDBMS.

How does the "With" keyword work in SQL?

So many times seen with and, so many times SQL Server ask that with has ; before it
How does ;with ... work??
;with coords(...) as (
SELECT * ...
)
Why must have ; before it?
The semicolon is used in SQL to end a query. Putting it before a query like that is just to make sure that the database understands that any previous query has ended.
Originally it was required after each query as they were entered line by line, so the database had to know when to run the query. When the entire query is sent in a single string, you only need semicolons in the case where the SQL syntax is not enough to determine where a query ends. As the with keyword has different uses a semicolon is sometimes needed before it to make sure that it's not part of the previous query.
Using WITH for CTEs requires the previous statement to be terminated with ;. Using it at the start like this guarantees correct syntax
So does MERGE in SQL Server 2008
See this SO question: Incorrect syntax near the keyword 'with'...previous statement must be terminated with a semicolon
It is best practise to terminate every SQL statement with a semicolon. The SQL Server docs (for example here) suggest doing so will be mandated in a future version to there's really no excuse for not getting into the habit now.
To answer the question: you see ;WITH... on Stackoverflow because EITHER the person answering is a sloppy coder OR the person answering assumes the person asking the question is a sloppy coder (and they'll claim it is the latter when it is the former :) The definition of "sloppy coder" here is someone who only uses a semicolon when they are forced to do so.
The use of WITH is for common table expressions (CTEs). They were trying to force the CTE to be defined as the first statement (i.e. cannot be linked with other parts of the query hence the ;)

How do I deal with quotes ' in SQL [duplicate]

This question already has answers here:
How to anticipate and escape single quote ' in oracle
(2 answers)
Closed 7 years ago.
I have a database with names in it such as John Doe etc. Unfortunately some of these names contain quotes like Keiran O'Keefe. Now when I try and search for such names as follows:
SELECT * FROM PEOPLE WHERE SURNAME='O'Keefe'
I (understandably) get an error.
How do I prevent this error from occurring. I am using Oracle and PLSQL.
The escape character is ', so you would need to replace the quote with two quotes.
For example,
SELECT * FROM PEOPLE WHERE SURNAME='O'Keefe'
becomes
SELECT * FROM PEOPLE WHERE SURNAME='O''Keefe'
That said, it's probably incorrect to do this yourself. Your language may have a function to escape strings for use in SQL, but an even better option is to use parameters. Usually this works as follows.
Your SQL command would be :
SELECT * FROM PEOPLE WHERE SURNAME=?
Then, when you execute it, you pass in "O'Keefe" as a parameter.
Because the SQL is parsed before the parameter value is set, there's no way for the parameter value to alter the structure of the SQL (and it's even a little faster if you want to run the same statement several times with different parameters).
I should also point out that, while your example just causes an error, you open youself up to a lot of other problems by not escaping strings appropriately. See http://en.wikipedia.org/wiki/SQL_injection for a good starting point or the following classic xkcd comic.
Oracle 10 solution is
SELECT * FROM PEOPLE WHERE SURNAME=q'{O'Keefe}'
Parameterized queries are your friend, as suggested by Matt.
Command = SELECT * FROM PEOPLE WHERE SURNAME=?
They will protect you from headaches involved with
Strings with quotes
Querying using dates
SQL Injection
Use of parameterized SQL has other benefits, it reduces CPU overhead (as well as other resources) in Oracle by reducing the amount of work Oracle requires in order to parse the statement. If you do not use parameters (we call them bind variables in Oracle) then "select * from foo where bar='cat'" and "select * from foo where bar='dog'" are treated as separate statements, where as "select * from foo where bar=:b1" is the same statement, meaning things like syntax, validity of objects that are referenced etc...do not need to be checked again. There are occasional problems that arise when using bind variables which usually manifests itself in not getting the most efficient SQL execution plan but there are workarounds for this and these problems really depend on the predicates you are using, indexing and data skew.
Input filtering is usually done on the language level rather than database layers.
php and .NET both have their respective libraries for escaping sql statements. Check your language, see waht's available.
If your data are trustable, then you can just do a string replace to add another ' infront of the ' to escape it. Usually that is enough if there isn't any risks that the input is malicious.
I suppose a good question is what language are you using?
In PHP you would do: SELECT * FROM PEOPLE WHERE SURNAME='mysql_escape_string(O'Keefe)'
But since you didn't specify the language I will suggest that you look into a escape string function mysql or otherwise in your language.
To deal quotes if you're using Zend Framework here is the code
$db = Zend_Db_Table_Abstract::getDefaultAdapter();
$db->quoteInto('your_query_here = ?','your_value_here');
for example ;
//SELECT * FROM PEOPLE WHERE SURNAME='O'Keefe' will become
SELECT * FROM PEOPLE WHERE SURNAME='\'O\'Keefe\''
Found in under 30s on Google...
Oracle SQL FAQ