How should date-based queries in Oracle be parameterised - sql

ResultSet rs=st.executeQuery(
"select j.vc_jo_no,
j.dt_jo_date,
p.vc_product_name
from mst_jobcard j,
mst_prod p
where j.vc_product_code=p.vc_product_code
and j.dt_jo_date=to_char("+tdate+","+"'"+dd-mm-yy+"'"+")
");
In my specified query it should display the records based on the date parameter that is being passed in the above query.
the vc_jo_no,dt_jo_date are taken from mst_jobcard table and vc_product_name is taken from mst_prod table.
i have joined the tables.
please help me in how to use the to_char function for date.
when i specify the format i.e dd-mm-yy in the to_char function it gives error.
please help..

If you're going to pass the date as a string Oracle needs it surrounded by single quotes. Also, the "dd-mm-yy" doesn't look right to me. Try this:
ResultSet rs=st.executeQuery(
"select j.vc_jo_no,
j.dt_jo_date,
p.vc_product_name
from mst_jobcard j,
mst_prod p
where j.vc_product_code=p.vc_product_code
and j.dt_jo_date=to_char('"+tdate+"','dd-mm-yy')
");
That said, this method of passing parameters is effectively NOT passing the parameter - it will cause the database to parse a different query for every different date requested, which is likely to cause a scalability issue.
The better approach would be to bind the parameter, using whatever method is provided by ResultSet to bind a variable. You may find you can even bind a date variable natively without having to convert it to a string.

So you're running:
executeQuery("select … where … j.dt_jo_date=to_char("+tdate+","+"'"+dd-mm-yy+"'"+")");
First thing, try put that string in a variable, output it and see if it's in the correct format.
Have you tried:
"… to_char("+tdate+",'dd-mm-yy'")
it seems you're doing unnecessary acrobatics with that string.
And finally, take a look at "Oracle to_char usage" by Burleson Consulting. It was the first link off of Google. Some say Google's a good place to look first.

Related

Data Factory expression substring? Is there a function similar like right?

Please help,
How could I extract 2019-04-02 out of the following string with Azure data flow expression?
ABC_DATASET-2019-04-02T02:10:03.5249248Z.parquet
The first part of the string received as a ChildItem from a GetMetaData activity is dynamically. So in this case it is ABC_DATASET that is dynamic.
Kind regards,
D
There are several ways to approach this problem, and they are really dependent on the format of the string value. Each of these approaches uses Derived Column to either create a new column or replace the existing column's value in the Data Flow.
Static format
If the format is always the same, meaning the length of the sections is always the same, then substring is simplest:
This will parse the string like so:
Useful reminder: substring and array indexes in Data Flow are 1-based.
Dynamic format
If the format of the base string is dynamic, things get a tad trickier. For this answer, I will assume that the basic format of {variabledata}-{timestamp}.parquet is consistent, so we can use the hyphen as a base delineator.
Derived Column has support for local variables, which is really useful when solving problems like this one. Let's start by creating a local variable to convert the string into an array based on the hyphen. This will lead to some other problems later since the string includes multiple hyphens thanks to the timestamp data, but we'll deal with that later. Inside the Derived Column Expression Builder, select "Locals":
On the right side, click "New" to create a local variable. We'll name it and define it using a split expression:
Press "OK" to save the local and go back to the Derived Column. Next, create another local variable for the yyyy portion of the date:
The cool part of this is I am now referencing the local variable array that I created in the previous step. I'll follow this pattern to create a local variable for MM too:
I'll do this one more time for the dd portion, but this time I have to do a bit more to get rid of all the extraneous data at the end of the string. Substring again turns out to be a good solution:
Now that I have the components I need isolated as variables, we just reconstruct them using string interpolation in the Derived Column:
Back in our data preview, we can see the results:
Where else to go from here
If these solutions don't address your problem, then you have to get creative. Here are some other functions that may help:
regexSplit
left
right
dropLeft
dropRight

Why would SQL statement return out of ordered dataset?

I have written a program that logs events into a db file as they happen using SQL statement. Whenever I open the table to view, I specifically request the dataset in descending order based on ALARM's date and time. It seems to work only for part of the table. I am using SQLite3 and my program is written in delphi or Pascal.
Here is the SQL statement:
SELECT *
FROM Alarms
ORDER BY datetime(ALARMTIME) DESC
Here is a snapshot of the table. Pay attention to the red arrows. That's where Alarm's date and time doesn't follow descending order. I don't know why this is happening.
I'm not sure how you created your date/time string in your database since that information wasn't given in the question. However, according to the documentation for the datetime() function, the format you have of MM/DD/YYYY HH:MM:SS xx is not one of the accepted formats. In fact, if you do SELECT datetime('1/23/2018 01:40:00 PM') at an SQLite prompt, you get NULL. Whereas, if you use an acceptable format, you do not: SELECT datetime('2018-01-23') gives '2018-01-23 00:00:00'.
So I think the solution is to write the ALARMTIME field using datetime('now'), which does yield a format accepted by datetime(). If you need to sort based upon the format you have now, you can't do it with datetime(). You'd need to reformat the field using string functions to get it in a form you could do a string compare with (e.g., as is done here).
The OP has indicated in a comment that the ALARMTIME is set using the following Pascal code:
FieldByName('AlarmTime').AsDateTime := now;
There's no guarantee that Pascal is going to use a date/time string format in this context that is compatible with SQLite's datetime() function. So Pascal date/time formatting functions can be used to create a format more specifically acceptable by SQLite's datetime(). Then you'd use something like:
FieldByName('AlarmTime').AsString := FormatDateTime('YYYY-MM-DD hh:nn:ss',now);
Now this will change the default view of the date to YYYY-MM-DD .... If you still want your view of the table to show MM/DD/YYYY... then you'll either need to go back to my prior comment about processing the string on the fly in the comparison for sort, or write a little view formatting code so that it displays in a format that's different than what is stored internally, which is a common view/model separation technique.
If you can write your original ALARMTIME format as MM/DD/YYYY and make sure you pre-pad with zeroes (e.g., 01/09/2018 not 1/9/2018) then you can use SQLite's substr function:
SELECT * FROM Alarms
ORDER BY (substr(ALARMTIME,7,4)||substr(ALARMTIME,1,2)||substr(ALARMTIME,4,2)||substr(ALARMTIME,11)) DESC
And you would create your ALARMTIME using this:
FieldByName('AlarmTime').AsString := FormatDateTime('dd-mm-yyyy hh:nn:ss', now);
The above solutions are fairly generic. Depending upon the client library you are using (which you have not specified), there may be another more suitable approach to solving the problem.
You cannot do, for example, SELECT * FROM Alarms ORDER BY ALARMTIME DESC and get an accurate sort since, for example, the date 12/1/2018 would come after 2/1/2018 in that sort ordering even though 2/1/2018 is later in time. This is because 2 follows 1 in the ASCII collating sequence.
If you need to keep your current ALARMTIME string format and not change how you're saving it, which is somewhat free form m/d/yyyy in which the day or month can have one or two digits, you're going to have a bit of work to do in order to sort it if your client library doesn't support some helpers in this regard. Perhaps your only other option would be to use a custom SQLite function. These are written in C and compiled and linked with SQLite. You'd have to find one already written, or write your own.

Convert all selected columns to_char

I am using oracle SQL queries in an external Program (Pentaho Data Integration (PDI)).
I need to convert all columns to string values before I can proceed with using them.
What i am looking for is something that automatically applies the
select to_date(col1), to_date(col2),..., to_date(colN) from example_table;
to all columns, so that you might at best wrap this statement:
select * from example_table;
and all columns are automatically converted.
For explanation: I need this because PDI doesn't seem to work fine when getting uncasted DATE columns. Since I have dynamic queries, I do not know if a DATE column exists and simply want to convert all columns to strings.
EDIT
Since the queries vary and since I have a long list of them as an input, I am looking for a more generic method than just manually writing to_char() infront of every column.
If you are looking for a solution in PDI, you need to create a job (.kjb) where in you take 2 transformations. First .ktr will rebuild the query and the Second .ktr will execute the new query.
1. First Transformation: Rebuild the query
Read the columns in the Source Table Step (use Table Input step in your case). Write the query select * from example_table; and limit the rows to either 0 or 1. The idea here is not to fetch all the rows but to recreate the query.
Use Meta Structure Step to get the meta-structure of the table. It will fetch you the list of columns coming in from the prev. step.
In the Modified JavaScript step, use a small snip of code to check if the data type of column is Date and then concat to_Char(column) to the rows.
Finally Group and Set the variables into a variable.
This is the point where the fields are recreated for you automatically. Now the next step is to execute this field with the new query.
2. Second Transformation: Using this set variable in the next step to get the result. ${NWFIELDNAME} is the variable you have set with the modified column in the above transformation.
Hope this helps :)
I have placed the code for the first ktr in gist here.
select TO_CHAR(*) from example_table;
You should not use * in your production code, it is a bad coding practice. You should explicitly mention the column names which you want to fetch.
Also, TO_CHAR(*) makes no sense. How would you convert date to string? You must use proper format model.
In conclusion, it would take a minute or two at max to list down the column names using a good text editor.
I can so not immagine an application that does not know about the actual data types but if you really want to automa(gi)cally convert all columns to strings, I see two possibilities in Oracle:
If your application language allows you to specify the binding type, you simply bind all your output variables to a string variable. The Oracle driver than takes care to convert all types to strings and this is for example possible with jdbc (Java).
If (as it seems) your application language does not allow the first solution, the best way I could think of, is to define a view for each select you want to use with the appropriate TO_CHAR convertions already and then select from the view. Those views could eventually also be generated automatically from the table repository (user_table) with some PL/SQL.
Please also note, that TO_CHAR will convert your columns acccording to the NLS settings of your session and this might lead to unwanted results, so you might also want to always specify how to convert:
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD') FROM DUAL;
using these 2 tables, you could write a procedure with looks at the columns on each table and then performs the appropriate TO_CHAR depending on the current datatype
select * from user_tab_columns
select * from user_tables
psuedo code
begin
loop on table -- user_tables
loop on column -- user_tab_columns
if current data_type = DATE then
lnewColumn = TO_CHAR(oldColumn...(
elsif current data_type = NUMBER then
...

How would I use an sql query with .where to check for a match between a date column and a string?

I have a hunch that this is sort of a hack already, but I was curious about this nonetheless:
Say I have this:
current_user.memories.where("content LIKE '%#{search}%' OR note LIKE '%#{search}%' OR date LIKE '%#{search}%'")
This is for a search field.
In my database, in the 'memories' table, I have content:text and note:string, so up through the first two compares, this trick works fine.
However, the date part doesn't work, obviously. I have a date:date column in the memories table too, but I don't know how to check for a match with the string.
I am fine with formatting the string to something like 2013-01-15, but I don't know how to do this comparison. Somehow change the 'date' part into that string too?
The idea behind this whole thing is to allow a search like 2013-01-15 (or some format) which would automatically check for dates too for 'memory' objects.
Advice appreciated.
(The db is postgres if that matters.)
First of all, you shouldn't be using string interpolation to build SQL, let ActiveRecord take care of that stuff. Secondly, if your search is in ISO 8601 format (i.e. YYYY-MM-DD) then you could directly compare the date column with the string use = and PostgreSQL will figure it out. You want something more like this:
current_user.memories.where(%q{
content like :pat
or note like :pat
or date = :date
}, :pat => "%#{search}%", :date => search)
You could convert your search term into a date by using to_date(text, text). You may also have to remove the time component from your date field if necessary
An explanation is here

Is there a quick way to re-format all values in a ColdFusion query column?

I am at the liberty of a certain database, which stores date values as integers (i.e. 20121119). I have several queries that retrieve these values for reporting displays, so I need to convert these values to m/d/yyyy format.
I see several ways to do this:
Do the conversion in the display, using an existing global UDF. The drawback here, is that if the query is re-used, I need to duplicate the code necessary to convert the display value.
Parse the value in the SQL to return a properly formatted value. I'm reading from a DB2/iSeries, which does not (as far as I have found) have a built-in function for this.
Loop over the result set and convert each value one at a time. This is what I am currently doing, however for larger data-sets, performance is an issue:
<cfscript>
var i = 1;
var _query = ARGUMENTS.query;
if ( !Len(Trim(ARGUMENTS.column))
|| !ListFindNoCase(_query.ColumnList, ARGUMENTS.column))
return _query;
for (i=1; i<=_query.RecordCount; i++) {
_query[ARGUMENTS.column][i] =
VARIABLES.Library.DateTime.ParseAS400Date(
_query[ARGUMENTS.column][i]
);
}
return _query;
</cfscript>
Is there an easy/quick way to apply a formatting function to an entire column in a ColdFusion query object?
As noted by #Dan, there is a built-in function that will convert a string to a timestamp representation. Since you have an int, then it would be something like this:
SELECT VARCHAR_FORMAT(TIMESTAMP_FORMAT(CAST(20121119 AS CHAR(8)), 'YYYYMMDD'), 'MM/DD/YYYY')
FROM SYSIBM.SYSDUMMY1
This page might help you with the parsing in db2 you didn't know about. Format date to string
Edit: Oops, you said it was an integer. The cast() function will convert it to character and then you can use concat() and substr() to format it.
Using that function would be my approach.
Do the conversion in the display, using an existing global UDF.
This is the right way to handle this problem. Typically, formatting should not be applied to a data model (which is essentially what your query result is). Formatting should be applied when the data is displayed. This allows you to format the data differently when it is displayed in different contexts. Also, it improves code readability.
The drawback here, is that if the query is re-used, I need to duplicate the code necessary to convert the display value.
This is not a drawback. You will be formatting the data for presentation any time you are displaying data. Formatting a date is no different.
Calling a function that formats your data more than once is not "code duplication". You are simply using the formatting function as it was intended to be used.