2011-12-30 9 views
5

मैं कल इस समस्या पर ठोकर खाई जब मैं SQLLite का उपयोग कर कुछ इकाई परीक्षण लेखन में व्यस्त था खो देता है। मेरा पर्यावरण विंडोज 7/डेल्फी एक्सई है।एडीओ (ODBC) के साथ एक datetime पैरामीटर का उपयोग समय भाग

समय हिस्से के नुकसान में एक TDateTime पैरामीटर परिणामों के साथ संयोजन के रूप में TADOQuery का उपयोग करना।

unit Unit1; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, ADODb, DateUtils, DB; 

type 
    TForm1 = class(TForm) 
    procedure FormCreate(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.FormCreate(Sender: TObject); 

var DbConn : TADOConnection; 
    Qry : TADOQuery; 
    DT  : TDateTime; 

begin 
DBConn := TADOConnection.Create(nil); 
DBConn.ConnectionString := 'Provider=MSDASQL.1;Extended Properties="DRIVER=SQLite3 ODBC Driver;Database=:memory:;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;"'; 
// DBConn.ConnectionString := 'Provider=MSDASQL.1;Persist Security Info=True;User ID=%0:s;Password=%1:s;Extended Properties="DRIVER={MySQL ODBC 5.1 Driver};SERVER=localhost;PORT=3306;DATABASE=test;USER=root;PASSWORD=rrr;OPTION=1048579"'; 
Qry := TADOQuery.Create(nil); 
Qry.Connection := DbConn; 
try 
    DBConn.Connected := True; 
    Qry.SQL.Text := 'CREATE TABLE test(d datetime)'; 
    Qry.ExecSQL; 
    Qry.ParamCheck := True; 
    Qry.SQL.Text := 'INSERT INTO test (d) VALUES (:d)'; 
    //Qry.Parameters.ParseSQL(Qry.SQL.Text, True); // not needed 
    TryEncodeDateTime(1999, 12, 12, 10, 59, 12, 0, DT); 
    Qry.Parameters.ParamByName('d').Value := DT; 
    Qry.Parameters.ParamByName('d').DataType := ftDateTime; 
    Qry.ExecSQL; 
    Qry.SQL.Text := 'SELECT d FROM test'; 
    Qry.Open; 
    ShowMessage(FormatDateTime('MM/DD/YYYY HH:NN:SS', Qry.FieldByName('d').AsDateTime)); 
finally 
    FreeAndNil(Qry); 
    FreeAndNil(DbConn); 
end; 
end; 

अजीब बात है जब मैं लाइन Qry.Parameters.ParseSQL(Qry.SQL.Text, True); टिप्पणी यह ​​ठीक काम करेंगे, है। मुझे ParseSQL भाग की आवश्यकता है क्योंकि मैं मिनी-ओआरएम बना रहा हूं, इसलिए इसे जानना आवश्यक है कि किन पैरामीटर को मैप किया जाना है। कुछ टिप्पणियों:

  • MySQL5 साथ ही परीक्षण कर (चाहे ParseSQL भाग के) एक ही समस्या को दर्शाता है।
  • इस कोड को एसक्यूएल सर्वर और OLEDB ड्राइवर के साथ काम करता है।

मैं शुद्ध खोज की है और पाया है कुछ दिलचस्प लिंक:

http://tracker.firebirdsql.org/browse/ODBC-27

http://embarcadero.newsgroups.archived.at/public.delphi.database.ado/201107/1107112007.html

http://bugs.mysql.com/bug.php?id=15681

पहले लिंक का सुझाव 'फिक्सिंग' ADODB.pas, कुछ मैं करता हूँ नहीं करना चाहता अंतिम लिंक पढ़ना, ऐसा लगता है कि एडीओ डेटटाइम वैल्यू को आज तक मानचित्र करता है।

जवाब मैंने सुना है नहीं करना चाहती:

(dbExpress, Zeoslib, ...) की तरह एक और पुस्तकालय/घटक का उपयोग मुझे यकीन है कि क्या इस समस्या को हल करने के लिए सबसे समझदार दृष्टिकोण होना होगा नहीं हूँ।

रूप लिनस और मार्जन Venema सुझाव दिया मैं ParseSQL भाग को छोड़ सकते हैं। तो कोड अगर मैं लाइन Qry.Parameters.ParamByName('d').DataType := ftDateTime; छोड़ SQLlite के साथ अब काम करता है।

लेकिन MySQL समय हिस्सा बचाने के लिए मना कर दिया। क्या मैं यहां एडीओ और माईएसक्यूएल ओडीबीसी के बीच एक संगत समस्या देख रहा हूं?

+0

मैं डेटाटाइप _before_ मूल्य निर्धारित करने के लिए सेट करता हूं, लेकिन यह सुनिश्चित नहीं करता कि इससे कोई फर्क पड़ेगा। एक मिनी ओआरएम बनाने के लिए ParseSQL की आवश्यकता क्यों है? मैंने कुछ ओआरएम प्रकार के libs का निर्माण किया है और इसकी आवश्यकता नहीं है? आईआईआरसी Qry.SQL.Prepare भी पैरामीटर संग्रह पॉप्युलेट करना चाहिए। –

+0

मुझे यह जानने की ज़रूरत है कि मेरे प्रश्न में मेरे पास कौन से पैरामीटर हैं और मूल्यों को आरटीआई का उपयोग करके ऑब्जेक्ट से मैप किया जाएगा। आपका मतलब है Qry.Prepared: = true; ? कोई फर्क नहीं पड़ता। – whosrdaddy

+1

@whosrdaddy अपने आप ParseSQL को कॉल करने की आवश्यकता नहीं है। यह स्वचालित रूप से कहा जाता है जब SQL.Text बदलता है (पैराम चेक सही होना चाहिए)। – Linas

उत्तर

8

मैंने SQL सर्वर का उपयोग करके इसका थोड़ा सा परीक्षण किया है और जब मैं MSDASQL.1 (ODBC) का उपयोग करता हूं तो वही समस्या होती है। आपका कोड SQLOLEDB.1 और SQLNCLI10.1 के साथ ठीक काम करता है।

यदि आप ftString होने के लिए पैरामीटर प्रकार निर्दिष्ट करते हैं तो यह ओडीबीसी (कम से कम SQL सर्वर पर) का उपयोग करके समय के साथ बचाएगा।

Qry.Parameters.ParamByName('d').DataType := ftString; 
Qry.Parameters.ParamByName('d').Value := DateTimeToStr(DT); 

नोट: स्थानीय सेटिंग की सावधान जब आप DateTimeToStr का उपयोग यह उत्पन्न न कर पाए कि आपके db यह होना चाहता है रहो। एक सुरक्षित शर्त yyyy-mm-dd hh:mm:ss[.fff] का उपयोग करना होगा।

अद्यतन:

तुम भी अपने आप को adDBTimeStamp करने की हलचल के पैरामीटर के डेटा प्रकार सेट कर सकते हैं। जब आप ftDateTime का उपयोग करते हैं तो ADODB इसे adDate पर सेट करता है।

Qry.Parameters.ParamByName('d').ParameterObject.Type_ := adDBTimeStamp; 
Qry.Parameters.ParamByName('d').Value := DT; 
+0

स्ट्रिंग में कनवर्ट करना सिर्फ ऐप को क्रैश करता है। adDBTimeStamp हालांकि काम करता है। लेकिन अब मेरा मैपिंग कोड टूटा हुआ है, और मुझे EOleException मिल रहा है: "एप्लिकेशन वर्तमान ऑपरेशन के लिए गलत प्रकार के मान का उपयोग करता है"। लेकिन मुझे संदेह है कि यह संस्करणों के साथ एक मुद्दा है। आपके उत्तर के लिए धन्यवाद! – whosrdaddy

0

मैं एक ही (विजुअल फॉक्सप्रो चालक) VFPOLEDB साथ समस्या यह है लेकिन adDBTimeStamp साथ चाल काम नहीं किया था। एफडब्ल्यूआईडब्लू, यह डेल्फी 7 के साथ वीएफपीओएलडीबी 9.0.0.5815 और आरएडी स्टूडियो 10 (सिएटल) के साथ भी है।

वीएफपीओएलडीबी के मामले में एक और संभावित कार्यवाही है जो इस तथ्य पर आधारित है कि फॉक्स में तिथि/समय मानों के लिए अंतर्निहित प्रतिनिधित्व (प्रकार 'टी') दिनांक मानों के प्रकार के समान है (प्रकार 'डी ') ओएलडीडीबी द्वारा पारित किया गया, यानि 64-बिट डबल जहां पूर्णांक भाग वर्ष 0001 में 1 जनवरी से दिन का प्रतिनिधित्व करता है और आंशिक भाग दिन के समय का प्रतिनिधित्व करता है।

यदि तालिका फ़ील्ड में 'टी' टाइप किया गया है और ओएलडीडीबी एक तिथि पास करता है तो फॉक्स कुछ भी नहीं करके मूल्य को जोड़ता है। तो यहां जो कुछ भी जरूरी है वह आंशिक भाग में वापस जोड़ रहा है।

उदाहरण के लिए, start_time दिनांक/समय क्षेत्र होने के साथ:

cmd.CommandText := 'insert into foo (start_time) values (:start_time)'; 
cmd.Parameters.ParamByName('start_time') := Now; 
cmd.Execute; 

यह 2016-05-22 00:00:00 तालिका में देता है।

अब, इस तरह आंशिक हिस्सा जोड़ें:

cmd.CommandText := 'insert into foo (start_time) values (:start_time + :fraction)'; 
t := Now; 
cmd.Parameters.ParamByName('start_time') := t; 
cmd.Parameters.ParamByName('fraction') := Frac(t); 
cmd.Execute; 

यह 2016-05-22 02:17:42 देता है। यहां तक ​​कि आंशिक सेकंड संरक्षित भी होते हैं, हालांकि वे प्रदर्शित नहीं होते हैं।