I have to create dbf file in my Delphi application.
For this case I use ADODB.
Connection string:
const
ConnStringDBF =
'Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=%s;';
//'Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties=dBASE III;OLE DB Services=-1;Data Source=%s;';
//'Driver={Microsoft Visual Foxpro Driver};SourceType=DBF;SourceDB=%s;';
//Driver='Microsoft.ACE.OLEDB.12.0;Data Source=%s;';
And procedure (which doesn work):
procedure InsertRecordInDBF(file_name: string; DbfRecord: TDbfRecord);
var
ADOConnDBF : TADOConnection;
ADOCommand : TADOCommand;
begin
ADOConnDBF := TADOConnection.Create(nil);
ADOConnDBF.ConnectionString := Format(ConnStringDBF, [data_dir]);
ADOCommand := TADOCommand.Create(nil);
ADOCommand.Connection := ADOConnDBF;
ADOCommand.CommandText := 'Create Table ' + file_name + ' ('
+ 'NUMBER CHAR(11)'
+ ')'
;
ADOCommand.Execute;
end;
The error is:
raised exception class EOleException with message '[Microsoft][Драйвер ODBC dBase] Ошибка синтаксиса при определении поля'.
Which means: syntax error in translation from Russian.
But this CommandText works perfectly:
ADOCommand.CommandText := 'Create Table ' + file_name + ' ('
+ 'NUMBER_ CHAR(11)'
+ ')'
;
The difference in the name of the field (Number_ instead of Number)
How can I create table with field Number?
Maybe I need different connection string?
It seems that I found solution for this problem. The right syntax is:
ADOCommand.CommandText := 'Create Table ' + file_name + ' ('
+ '[NUMBER] CHAR(11)'
+ ')'
;
I added [] to the name of the field
Use VFPOLEDB provider with the following connection string:
Provider=VFPOLEDB.1;Data Source=%s;Password="";Collating Sequence=MACHINE
In this case your CREATE TABLE clause will work fine.
Related
You can skip straight to the code, if you want to. The leading text is explanation, but not necessary.
I am trying to use SuperObject to parse Delphi.
I was just using the plain JSON classes that come with Delphi 10.4, but had difficulty with some slightly complex functionality.
E.g stuff, such as does a.b.c exist, or a.b.c.d - where d is an array - or a.b.c.d[3].
And how to iterate over a.b.c.d. And to assign a value to a.b.c.d.e, updating it if it exists, creating it if not; and, if only part of the path exists, create it all e.g only a.b exists and I want to assign a value to a.b.c.d[3].e.
If anyone can point me to some examples of that sort of thing, I would be grateful.
Now, to my question. It seemed from various posts that SuperObject would be the answer, but I am failing at my first basic step - to test the existence of a nested JSN element.
Here's my code (is there an online JSON Fiddle site?)
unit fMainForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses System.IOUtils,
SuperObject;
procedure TForm1.FormCreate(Sender: TObject);
var json: ISuperObject;
jsonString : String;
begin
// Example JSON taken from https://stackoverflow.com/questions/10539797/complex-json-nesting-of-objects-and-arrays
jsonString := '{' +
'"problems": [{' +
' "Diabetes":[{' +
' "medications":[{' +
' "medicationsClasses":[{' +
' "className":[{' +
' "associatedDrug":[{' +
' "name":"asprin",' +
' "dose":"",' +
' "strength":"500 mg"' +
' }],' +
' "associatedDrug#2":[{' +
' "name":"somethingElse",' +
' "dose":"",' +
' "strength":"500 mg"' +
' }]' +
' }],' +
' "className2":[{' +
' "associatedDrug":[{' +
' "name":"asprin",' +
' "dose":"",' +
' "strength":"500 mg"' +
' }],' +
' "associatedDrug#2":[{' +
' "name":"somethingElse",' +
' "dose":"",' +
' "strength":"500 mg"' +
' }]' +
' }]' +
' }]' +
' }],' +
' "labs":[{' +
' "missing_field": "missing_value"' +
' }]' +
' }],' +
' "Asthma":[{}]' +
'}]}';
json := SO(jsonString);
if json.AsObject.Exists('problems') then
Memo1.Lines.Add('"problems" found')
else
Memo1.Lines.Add('"problems" not found');
if json.AsObject.Exists('problems.Diabetes') then
Memo1.Lines.Add('"problems.Diabetes" found')
else
Memo1.Lines.Add('"problems.Diabetes" not found');
end;
end.
When I run it, the memo contains
"problems" found
"problems.Diabetes" not found
How do I test for the existence of problems.Diabetes?
If I can crack that, I will try to update the strength of an associatedDrug, then insert a new key/value pair into the associatedDrug, then extend an existing key by adding several depths.
You've picked one of the worst JSON examples, because its structure needlessly puts everything into arrays (always [{ and ]}) when array elements would be enough already. You should have grabbed an easier example and start with that, to get familiar with what an object is and what an array is. Likewise I restructured and shortened the JSON data to make it tinier and more clear. If you managed to understand that you can go on and reach your strength property:
uses
SuperObject;
var
json, next: ISuperObject;
text: String;
sts: TSuperTableString;
sa: TSuperArray;
i: Integer;
begin
text:=
'{' + // {Object} starts
' "problems": [' + // 1st "property" of object, value is an [array]
' {' + // 1st [element] of array is an {object}
' "Diabetes": "yes"' + // 1st "property" of object is a "text"
' }' + // {Object} ends after just 1 "property"
' ],' + // [Array] ends after just 1 [element]
' "Asthma": [' + // 2nd "property" of object, value is an [array] again
' {}' + // 1st [element] of array is an (empty) {object}
' ]' + // [Array] ends after just 1 [element]
'}'; // {Object} ends after 2 "properties"
json:= SO( text );
if json.IsType( stObject ) then begin // Is this even JSON (which must be an object)?
sts:= json.AsObject;
if sts.Find( 'problems', next ) then begin // Does a property "problems" exist?
if next.IsType( stArray ) then begin // Is its value an array?
sa:= next.AsArray;
for i:= 0 to sa.Length- 1 do begin // Iterate all array elements
next:= sa[i];
if next.IsType( stObject ) then begin // Is this element an object?
sts:= next.AsObject;
sts.S['key']:= 'value'; // Adding our own property "key" to that object
if sts.Find( {'Diabetes'} 'key', next ) then begin // Does a property "key" exist?
Caption:= 'Found it!';
if next.IsType( stString ) then begin // Is the property of type "text"?
Caption:= Caption+ ' Value='+ next.AsString; // Should be "value"
end;
break; // Leave array loop
end;
end;
end;
end;
end;
end;
end;
Single step through it with the debugger to see how every check is necessary to finally even reach the property Diabetes and to then check if its value is actually a text (and not another object/array).
A better format of that initial JSON data would be this, freed from needless arrays and using also numbers as datatypes instead of texts only (the syntax is valid, it may look odd for you but I think this is a more logical display):
{ "problems":
{ "Diabetes":
{ "medications":
[
[
{ "name": "Asprin"
, "strength_mg": 500
}
,
{ "name": "Arsen"
, "strength_mg": 20
}
]
,
[
{ "name": "Toracin"
, "strength_ml": 10
}
,
{ "name": "Ambroxol"
, "strength_mg": 350
}
]
]
, "labs":
{ "test_chamber": 3
}
}
, "Asthma": null
}
, "is_insured": false
}
You have an array problems with an other array Diabetes. You can simply do :
if Assigned(json['problems[0].Diabetes[0]']) then
Memo1.Lines.Add('problems found + Diabetes found');
Or loop inside both array :
if Assigned(json['problems']) then
begin
for i := 0 to json['problems'].AsArray.Length - 1 do
begin
Memo1.Lines.Add('"problems" found');
if Assigned(json['problems'].AsArray[i]['Diabetes']) then
begin
for j := 0 to json['problems'].AsArray[i]['Diabetes'].AsArray.Length - 1 do
Memo1.Lines.Add('"problems.Diabetes" found')
end
else
Memo1.Lines.Add('"problems.Diabetes" not found');
end;
end
else
Memo1.Lines.Add('"problems" not found');
If you are not familiar with Delphi / JSON, use System.JSON is easier to use than this external lib
I am writing an application responsible for archiving data and we have the configuration in a database table
Id | TableName | ColumnName | RetentionAmountInDays
1 | DeviceData | MetricTime | 3
So when faced with this configuration, I should archive all data in the DeviceData table where the MetricTime value is before 3 days ago.
The reason I am doing this dynamically is the table names and column names differ (there would be multiple rows)
For each configuration this stored procedure is called
CREATE PROCEDURE GetDynamicDataForArchive
#TableName nvarchar(100),
#ColumnName nvarchar(100),
#OlderThanDate datetime2(7)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql nvarchar(1000);
SET #sql = 'SELECT * FROM ' + #TableName + ' WHERE ' + #ColumnName + ' < #OlderThanDate';
exec sp_executesql #sql;
END
And an example exec line
exec dbo.GetDynamicDataForArchive 'DeviceData', 'MetricTime', '2017-04-16 20:29:29.647'
This results in:
Conversion failed when converting date and/or time from character string.
So something is up with how I am passing in the datetime2 or how I am forming the where clause.
Replace this statement:
SET #sql = 'SELECT * FROM ' + #TableName + ' WHERE ' + #ColumnName + ' < #OlderThanDate'
by
SET #sql = 'SELECT * FROM ' + #TableName + ' WHERE [' + #ColumnName + '] < ''' + cast(#OlderThanDate as varchar(23)) + '''';
I don't particularly like having to convert the datetime to a varchar value though, perhaps there is a better way to do this(?).
I am newbie to IBM db2.Need to convert the below mentioned SP to db2 syntax. But i am stuck with many equivalents used or available in Db2. Even google research doesn't show how exactly we can compare object id of tables in db2 as I am doing in SQL Server stored procedure. Could anyone suggest me with right way to proceed?
EDIT: I have updated with equivalent DB2 syntax, but facing below error while deploying at the particular line, Can anyone identify and help me understand what is wrong with this syntax or the problem lies anywhere else in the procedure.
line no 25 : DECLARE v_sqlstate CHAR(5);
BACKUPTABLE: 25: An unexpected token "<variable declaration> was found following "". Expected tokens may include: "".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.18.60
An unexpected token variable declaration was found following "". Expected tokens may include: "".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.18.60
SQL Server Stored procedure syntax:
CREATE PROCEDURE [dbo].[BackUpTable]
#TableName sysname
AS
BEGIN
SET nocount ON
DECLARE #sql VARCHAR(500)
IF EXISTS (SELECT *
FROM sys.objects
WHERE object_id = Object_id(N'[dbo].[' + #TableName+'_EST' + ']')
AND TYPE IN ( N'U' ))
BEGIN
SET #sql = 'declare #Done bit
set #Done = 0
while #Done = 0
begin
delete top (100000)
from ' + #TableName + '_Bak' +
' if ##rowcount = 0
set #Done = 1
end;'
SET #sql = #sql + 'insert into ' + #TableName + '_Bak select * from ' +
#TableName +'_EST'
EXEC(#sql)
END
ELSE
BEGIN
DECLARE #err_message VARCHAR(300)
SELECT #err_message = 'The table "' + Isnull(#TableName, 'null') +
'" does not exist'
RAISERROR (#err_message, 16, 1)
END
END
DB2 SYNTAX CREATED SO FAR:
CREATE OR REPLACE PROCEDURE BackUpTable (IN TableName VARCHAR(128))
DYNAMIC RESULT SETS 1
BEGIN
DECLARE dynamicSql VARCHAR(500);
IF(EXISTS(
SELECT * FROM SYSIBM.SYSTABLES
WHERE NAME = TableName||'_EST'
)
)
THEN
SET dynamicSql = 'DELETE FROM '||TableName ||'_BAK';
SET dynamicSql = dynamicSql ||'insert into ' || TableName || '_BAK select * from ' ||
TableName || '_EST';
EXECUTE IMMEDIATE dynamicSql;
ELSE
DECLARE v_sqlstate CHAR(5);
DECLARE v_sqlcode INT;
DECLARE SQLSTATE CHAR(5) DEFAULT '00000';
DECLARE SQLCODE INT DEFAULT 0;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT SQLSTATE, SQLCODE
INTO v_sqlstate, v_sqlcode
FROM sysibm.sysdummy1;
SET O_Error_Msg = 'TABLE IS NOT AVAILABLE:: SQLState : '||v_sqlstate||' SQLCode : '||v_sqlcode ;
END;
END IF;
END
on z/os you can do it:
IF( EXISTS( SELECT 1 FROM QSYS2.SYSTABLES WHERE TABLE_SCHEMA = 'YOURLIB' AND TABLE_NAME = 'YOURTABLENAME')) THEN
DROP TABLE YOURLIB.YOURTABLENAME;
END IF;
Delphi XE5 + CIS 7.8 for XE5,when POST use Chinese formfield value like below
clHttpRequest.AddFormField('Status', '待处理');
itAutoStatus := '待处理' ;
mmo1.Lines.Add( ' 汉字为 : <'+ itAutoStatus +'>' ) ; // <待处理>
a2us := AnsiToUtf8(itAutoStatus) ;
mmo1.Lines.Add( ' 汉字AnsiToUtf8为 : <' + a2us +'>' ) ; // <待处理>
gbs := HTTPEncode(itAutoStatus);
mmo1.Lines.Add( ' 汉字HTTPEncode为 : <' + gbs +'>' ) ; // <%B4%FD%B4%A6%C0%ED>
utfs := HTTPEncode(AnsiToUtf8(itAutoStatus));
mmo1.Lines.Add( ' 汉字HTTPEncode(AnsiToUtf8())为 : <' + utfs +'>' ) ; // <%E5%BE%85%E5%A4%84%E7%90%86>
in IE8,right raw stream is : pageNo=1&total=&SortField=&SortType=&PromTitle=&C1=&Status=%E5%BE%85%E5%A4%84%E7%90%86
clHttpRequest.AddFormField('Status', '待处理');
CIS default raw stream is : pageNo=1&total=&SortField=&SortType=&PromTitle=&C1=&Status=%B4%FD%B4%A6%C0%ED
clHttpRequest.AddFormField('Status', HTTPEncode(AnsiToUtf8('待处理')));
Now CIS raw stream is : pageNo=1&total=&SortField=&SortType=&PromTitle=&C1=&Status=%25E5%25BE%2585%25E5%25A4%2584%25E7%2590%2586
clHttpRequest.AddFormField add string '25',so web server will no database query result.
I want to make raw stream like IE8,How to fix this? thanks!!!
solved
clHttpRequest.Header.CharSet := 'UTF-8';
CREATE OR REPLACE PROCEDURE STATUS_MAIL(FROM_MAIL IN VARCHAR2, TO_MAIL IN VARCHAR2)
is
v_From VARCHAR2(80) := FROM_MAIL;
v_Recipient VARCHAR2(80) := TO_MAIL;
v_Subject VARCHAR2(80) := 'EMPLOYEE STATUS';
v_Mail_Host VARCHAR2(30) := 'xx.xx.xxx.xxx';
v_Mail_Conn utl_smtp.Connection;
v_msg_body VARCHAR2(5000);
v_output VARCHAR2(5000);
BEGIN
/*Result always returns 42 rows*/
v_output := 'select empid,ename,mobile,dept from employee';
EXECUTE IMMEDIATE v_output into v_msg_body;
v_Mail_Conn := utl_smtp.Open_Connection(v_Mail_Host, xx);
utl_smtp.Helo(v_Mail_Conn, v_Mail_Host);
utl_smtp.Mail(v_Mail_Conn, v_From);
utl_smtp.Rcpt(v_Mail_Conn, v_Recipient);
utl_smtp.Data(v_Mail_Conn,
'Date: ' || to_char(sysdate, 'Dy, DD Mon YYYY hh24:mi:ss') || UTL_TCP.crlf ||
'From: ' || v_From || UTL_TCP.crlf ||
'Subject: '|| v_Subject || UTL_TCP.crlf ||
'To: ' || v_Recipient || UTL_TCP.crlf ||
UTL_TCP.crlf || v_msg_body );
utl_smtp.Quit(v_mail_conn);
EXCEPTION
WHEN utl_smtp.Transient_Error OR utl_smtp.Permanent_Error then
raise_application_error(-20000, 'Unable to send mail: '||sqlerrm);
END;
Getting an error inconsistent datatypes
# EXECUTE IMMEDIATE v_output into v_msg_body
while executing the above procedure, please help me....
So in fact your real question is: "how do I aggregate multiple rows into a single string ?"
The answer is to use aggregate functions. Oracle has introduced listagg-function in 11gR2 that solves this problem nicely but in earlier releases one has to do a bit more work.
When you know the right keywords Google finds a plenty of great resources, e.g.
String Aggregation Techniques
listagg function in 11g release 2
the collect function in 10g
I have collected the following examples from the above mentioned resources. Hope this gives you a good starting point:
The table that will be queried:
create table foo (d1 number, d2 varchar2(10));
insert all
into foo values(1, 'a')
into foo values(2, 'b')
into foo values(3, 'c')
select 1 from dual;
commit;
Oracle 11gR2:
declare
v_str varchar2(32767);
begin
select listagg('key = ' || d1 || ' value = ' || d2, chr(10))
within group (order by d1)
into v_str
from foo;
dbms_output.put_line(v_str);
exception
when value_error then
dbms_output.put_line('Exception: trying to insert too many characters to a varchar2 variable.');
end;
/
Oracle 10g:
create or replace type str_list_t as table of varchar2(32676);
/
create function to_string (
nt_in in str_list_t,
delimiter_in in varchar2 default ','
) return varchar2 is
v_idx pls_integer;
v_str varchar2(32767);
v_dlm varchar2(10);
begin
v_idx := nt_in.first;
while v_idx is not null loop
v_str := v_str || v_dlm || nt_in(v_idx);
v_dlm := delimiter_in;
v_idx := nt_in.next(v_idx);
end loop;
return v_str;
end;
/
declare
v_str varchar2(32676);
begin
select to_string(cast(collect('key = ' || d1 || ' value = ' || d2) as str_list_t), chr(10))
into v_str
from foo;
dbms_output.put_line(v_str);
exception
when value_error then
dbms_output.put_line('Exception: trying to insert too many characters to a varchar2 variable.');
end;
/
Note how I'll catch value_error exception that will be raised if the aggregated string won't fit into the reserved varchar2 capacity.
Output of both examples:
key = 1 value = a
key = 2 value = b
key = 3 value = c