How to convert TDateTime to be used in a Oracle SQL request? - delphi

I use an Oracle DB and access it using FireDAC.
I need to add to a select SQL request, two specific dates selected by the user. For that I am using two TDateTimePicker components.
I use DateTimeToStr() to convert the date from TDateTimePicker and build the SQL request like this:
FormRelatorio.FDQuery1.SQL.Add('and(PCPEDC.DTFAT) BETWEEN' +
''''+DatetoSTR(DateTimeInicial.Date)+'''' + 'and' +
''''+DatetoSTR(DateTimeFinal.Date)+'''');
Unfortunately, I get a syntax error from the DB because the DB does not accept nor auto adjust the system from month to numeral, accepting only their acronyms and in English (EX: JAN, FEB, MAR etc ...).
Is there any possibility of changing the result?

That is not a TDateTimePicker issue. It is an issue with how to pass a TDateTime (Delphi data type for date and time) to a SQL query. Currently you built a SQL string and so you must provide yourself the translation from date to string in the format accepted by the DB. This is possible but not the way to do it.
Instead, use a parametrized SQL query and FireDAC will do the work for you:
FormRelatorio.FDQuery1.SQL.Add('and (PCPEDC.DTFAT BETWEEN :InicialDate and :FinaleDate)');
FormRelatorio.FDQuery1.ParamByName('InicialDate ').AsDateTime := DateTimeInicial.Date;
FormRelatorio.FDQuery1.ParamByName('FinaleDate').AsDateTime := DateTimeFinal.Date;
This will correctly work if the columns in the database are correctly defined (You didn't showed the table structure).
If FireDAC doesn't do the correct job, you can use Oracle's TO_DATE function and Delphi FormatDateTime:
FormRelatorio.FDQuery1.SQL.Add('and (PCPEDC.DTFAT BETWEEN TO_DATE(''' + FormatDateTime('DD/MM/YYYY', DateTimeInicial.Date) + ''', 'DD/MM/YYYY') and
TO_DATE(''' + FormatDateTime('DD/MM/YYYY', DateTimeFinal.Date) + ''', 'DD/MM/YYYY'));
Oracle's TO_DATE accept a format DD/MM/YYYY and Delphi's FormatDateTime also. This avoid specifying month name.
Disclaimer: I have no Oracle DB available to check what I wrote. I did it from my head. You've got the idea...

Related

Using a DateTime as paramter in stored procedures, conversion failed

I have created a stored procedure that takes a single DATETIME as its input parameter. When I try to pass in a date in the format of MM-DD-YYYY OR YYYY-MM-DD I get the error
Conversion failed when converting date and/or time from character string.
The date I am testing with is 2010-01-01 and if I take that and plug it right into the select statement from the stored procedure it woks fine. What do I have to do to use a DATETIME as a parameter?
Here is my code:
CREATE PROC dbo.WSL_ProjectSearchByDate
#param1 DATETIME --Search Date
AS
SET NOCOUNT ON;
DECLARE #STMT NVARCHAR(MAX)
SET #STMT =
'SELECT project AS Project,
project_desc AS Description
status_gl AS Status
FROM dbo.PJPROJ WITH (NOLOCK)
WHERE crtd_datetime >= ' + #param1 + '
OR lupd_datetime >= ' + #param1 + ';';
EDIT: I am fully aware this is not best practice to be using dynamic SQL, I don't have any say in the matter and this question is not about the merits of dynamic SQL and whether or not I should be using it. This is how I have been instructed to build my stored procedures and so I am doing that.
Change the parameter type to VARCHAR and add quotes to your dynamic SQL:
...
#param1 VARCHAR(10) --Search Date
...
WHERE crtd_datetime >= ''' + #param1 + '''
OR lupd_datetime >= ''' + #param1 + ''';';
or -
Apply a CONVERT to your parameter when constructing your dynamic SQL:
...
WHERE crtd_datetime >= ''' + CONVERT(VARCHAR, #param1, 120) + '''
OR lupd_datetime >= ''' + CONVERT(VARCHAR, #param1, 120) + ''';';
Various settings (language, date format) only influence how the DateTime is shown to you in SQL Server Management Studio - or how it is parsed when you attempt to convert a string to a DateTime.
There are many formats supported by SQL Server - see the MSDN Books Online on CAST and CONVERT. Most of those formats are dependent on what settings you have - therefore, these settings might work some times - and sometimes not.
The way to solve this is to use the (slightly adapted) ISO-8601 date format that is supported by SQL Server - this format works always - regardless of your SQL Server language and dateformat settings.
The ISO-8601 format is supported by SQL Server comes in two flavors:
YYYYMMDD for just dates (no time portion); note here: no dashes!, that's very important! YYYY-MM-DD is NOT independent of the dateformat settings in your SQL Server and will NOT work in all situations!
or:
YYYY-MM-DDTHH:MM:SS for dates and times - note here: this format has dashes (but they can be omitted), and a fixed T as delimiter between the date and time portion of your DATETIME.
This is valid for SQL Server 2000 and newer.
If you use SQL Server 2008 or newer and the DATE datatype (only DATE - not DATETIME!), then you can indeed also use the YYYY-MM-DD format and that will work, too, with any settings in your SQL Server.
Don't ask me why this whole topic is so tricky and somewhat confusing - that's just the way it is. But with the YYYYMMDD format, you should be fine for any version of SQL Server and for any language and dateformat setting in your SQL Server.
The recommendation for SQL Server 2008 and newer is to use DATE if you only need the date portion, and DATETIME2(n) when you need both date and time. You should try to start phasing out the DATETIME datatype if ever possible.
So in your concrete case, try this:
CREATE PROC dbo.WSL_ProjectSearchByDate
#param1 DATETIME2(0) --Search Date
-- #param1 DATETIME2(0) -- or use this, if you really only care about DATE - no time portion
AS
SET NOCOUNT ON;
SELECT
project AS Project,
project_desc AS Description
status_gl AS Status
FROM
dbo.PJPROJ
WHERE
crtd_datetime >= #param1
OR lupd_datetime >= #param1;

How do you apply a Delphi ADOTable filter to a date data type

in MS Access I am able to filter a date in a query like this:
ex.
SignUpDate > #31/12/2013#
this will make the database only show records where SignUpDate is in 2014 or newer
How will I do this in delphi?
dmGym.tblMembers.filter := 'SignUpDate > ''#31/12/2013#''' doesn't seem to work
please help it wil be greatly appreciated
You can try :
dmGym.tblMembers.Filter:='SignUpDate > 31/12/2013';
dmGym.tblMembers.Filtered:=True;
This will make the database only show records where SignUpDate is in 2014 or newer.
Good Luck.
I think you don't need the #s, try
[...].Filter := '12/31/2013'; // this is for Sql Server and tested
// for UK locale, for Access you may need to swap the dd and mm,
//and maybe even the yyyy as suggested by #kobik in a comment.
If you use a TDateTime field in a TAdoDataSet.Locate(), the function GetFilterStr plugs the # signs in for you (and makes a hash of it (spot the pun) when doing similar for string fields - see # signs in ADO locates (Delphi XE5)).
But setting a simple filter on a TAdoTable seems to bypass ADODB.GetFilterStr and does a direct assignment to its recordset's Filter property, so I'm guessing that if the #s are needed, they must be plugged in by the ADO/MDac layer.
Delphi stores the datetime as a real number. Today is 05 June 2016 and the interger part of the DateTime is 42,526. Date zero is the start of 1900. You need to generate a variable called DateInt.
Var
DateInt: integer
Date1: TDate;
Begin
DateInt := Trunc(Date1)
When you save a date, save DateInt in the BeforePost event handler. This is an extra field, but filtering is now easy. For example, your filter can now be
NewDateInt := Trunc(Date1);
Filter := ‘NewDate = DateInt’;
Try dmGym.tblMembers.filter := 'SignUpDate > #yyyy/mm/dd#' (2013/12/31)
-credit to kobik's comment

Datatype mismatch when querying DBase Date field via a Delphi ADO Query

I'm trying to resolve a bug in a archaic reporting tool that generates SQL dynamically and I'm running to a problem where I get a Data type mismatch error when the generated SQL queries a Date field from a Dbase table.
I've managed to replicate the same problem in a simple test app where the below query is loaded into a TADOQuery and activated.
SELECT *
FROM [QPERFSAL.DBF] QPERFSAL
WHERE ( QPERFSAL.PERFDATE = '21/01/2014' )
its obviously related to the date formatting but I've tried numerous formats but I still get the error
e.g. dd/mm/yyyy, mm/dd/yyyy, yyyy/mm/dd etc.
The obvious fix would be to used parameterised queries but as this is generated on the fly by a report tool, I can't use parameters :(
Is there something I'm missing or can I specify the date format at the ADO connection?
Thanks!
VFP OleDB Provider I believe also recognizes the DATE() function where you don't need to worry about yyyy-mm-dd or mm-dd-yyyy or dd-mm-yyyy formats. It will build into a proper date format column.
where QPERFSAL.PERFDATE = date( 2014, 1, 21 )
Now, if the "perfDate" column is that of a date/time, then you need to compare based on the date-only portion of the date/time field by using TTOD() (time-to-date function)
where TTOD( QPERFSAL.PERFDATE ) = date( 2014, 1, 21 )
Try to use as follows:
SELECT *
FROM [QPERFSAL.DBF] QPERFSAL
WHERE ( DTOC(QPERFSAL.PERFDATE) = '01/21/2014' )
Firstly, thanks to all that posted suggestions.
Alas, I tried them all but without success :(
thankfully, I found the solution while searching for something unrelated.
SELECT *
FROM [QPERFSAL.DBF] QPERFSAL
WHERE PERFDATE = Format('2014/12/06',"YYYY/MM/DD")
I'm not sure what effect this will have on localization but at least I can get the query to run now.

conversion error from string, when using params in SQL

using Delphi 2010 (Firebird [testing], MS Sql Server, Oracle [production])
The following is my SQL
SELECT p.script_no, MIN(p.start_Time) as startTime, MAX(p.end_Time) as endTime,
SUM(p.duration) as TotalDuration
FROM phase_times p
WHERE (p.script_no=:scriptNo) AND (Trunc(p.start_time) >= :beginDateRange) AND (Trunc(p.start_time) <= :endDateRange)
GROUP BY p.script_no
ParamByName('beginDateRange').AsDate:= Date - 30;
ParamByName('endDateRange').AsDate:= Date;
I am getting a "conversion error from string - 10-25-2012" and i am not sure why, since my datetime fields are in the "10/25/2012 9:20:49 AM" format in the database.
If i change it to the following : ParamByName('beginDateRange').AsString := formatDateTime('mm/dd/yyyy',Date - 30).....i get the error "conversion error from string - 10/25/2012"
reserching this error has provided me no new avenues, do you have any ideas?
According to the Interbase 6.0 manual, Embedded SQL guide, chapter 7, Firebird supports conversion from YYYY-MM-DD and YYYY-MM-DD HH:MM:SS.qqq. I also believe it supports American style shorthand dates (eg 1-JAN-2012) for conversion.
It may be there are some locale dependent conversion supported, but in general: use an actual date/timestamp type instead of a string.
UPDATE
I initially did not spot the TRUNC in your query: it is the cause of the conversion error as this function only works on numbers, see the manual entry for TRUNC.
Given your comment (and the respons of ain) I assume you are only interested in the date part, and want to ignore the time. If so, rewrite your use of TRUNC to:
CAST(<your-timestamp-field> AS DATE)
And the condition (Trunc(p.start_time) >= :beginDateRange) AND (Trunc(p.start_time) <= :endDateRange) to:
CAST(p.start_time AS DATE) BETWEEN :beginDateRange AND :endDateRange
Firebird doesn't support conversion from string to date and time value if string is in 12 hour format. Use 'dd.mm.yyyy hh:mm:ss' or 'mm/dd/yyyy hh:mm:ss' formats.
String to date/time conversions usually use user's locale.
So if you feed a date/time conversion function with string that does not match your date part of the locale - you will get similar errors.
Also specifying date/time values like "10/25/2012" is Locale dependent. So if you execute your program on a computer with different than US Locale (like Mine) - it's likely to fail if using "10/25/2012".
To be Locale independent I suggest two options:
Use StrToDateTime, specifying TFormatSettings
Use ISO 8601 for specifying date/time strings (but I don't think Delphi supports that...)
BTW programs like MS Sql, Excel etc. accept dates in ISO 8601. But you have to check this for FB.
Regarding this:
...since my datetime fields are in the "10/25/2012 9:20:49 AM" format in the database...
The internal storage of date/time fields varies between different DB Engines. What you see in your DB Management Software ("10/25/2012 9:20:49 AM" in your case) is the string representation of the data field, usually formatted (again) according your user Locale
if you connected with DB from Firebird 1.0 under the server Firebird 2.1 (for example) you need todo backup and restore under Firebird 2.1

I'm getting "Invalid month in date" trying to run this?

I'm trying to run the following db command against Informix:
delete from table1
where u_id in (select u_id
from table2
where c_id in (select c_id
from ptable
where name = 'Smith'
and dob = '29-08-1946'));
I pass this in as a string to the db.ExecuteNonQuery method in the MS Data Application block and I get the above error?
To get the date format '29-08-1946' to work, you need your DBDATE environment variable set to a value such as "DMY4-" (or "DMY4/"). These are standard variations for the UK (I used them for years; I now use "Y4MD-" exclusively, which matches both ISO 8601:2004 (Date formats) and ISO 9075 (SQL), except when debugging someone else's environment). There are other environment variables that can affect date formatting - quite a lot of them, in fact - but DBDATE takes priority over the others, so it is the big sledgehammer that fixes the problem.
One of the problems is that your notation using a plain string is not portable between US and UK (and ISO) settings of DBDATE. If you have a choice, the neutral constructor for dates is the MDY() function:
WHERE dob = MDY(8,29,1946)
This works regardless of the setting of DBDATE. You can probably use TO_DATE() too:
SELECT TO_DATE('29-08-1946', '%d-%m-%Y') FROM dual;
This generated '1946-08-29 00:00:00.00000' for me - the function generates a DATETIME YEAR TO FRACTION(5) value, but those convert reliably to DATE values in Informix.
You can also use the DATE() function or an explicit cast to DATE (either CAST('29-08-1946' AS DATE) or '29-08-1946'::DATE), but both of those are subject to the whims of the locale of the users.
Your date field is improperly formatted. Since there is no 29th month in the year 1946 that is what is causing the error.
I'd try just swapping the month and day. 08-29-1946.
The way the day and month parts of a date string are read in can depend on your computer's culture settings.
It is always safer to pass date strings to a database in the form 'dd-MMM-yyyy' (i.e. '29-aug-1946')
It's even safer to pass them as YYYY-MM-DD, the dd-MMM-yyyy in that example will fail on a server with a (for example) French locale.

Resources