delphi 参数化sql

曾经查过资料,后来忘了,现在做一下记录。

---------

在 sql 语句里占位使用 一个冒号和一个用来表示这个位置的符号, 例如:SELECT * FROM aTableName WHERE aCol =  :ColVal

SELECT * FROM aTableName WHERE aCol =  :ColVal

对占位了的地方赋值这里使用的是 paremeters 属性的 paramByName 作的, 例如:

LDataSet.Parameters.ParamByName('ColVal').Value := 'SomeValue';

---------

最近在 Delphi 7 中通过参数化的方式存汉字字符串,出现只存入了一部分的情况,搜索资料并测试之后,发现设置 DataType = ftWideString 可以解决。

示例:

LCommand.Parameters.ParamByName('AKeyName').DataType := ftWideString;
LCommand.Parameters.ParamByName('AKeyName').Value := '我没有,我不是,别瞎说';

DataType 的类型:DB.pas/TFieldType

--date=2019-08-16

 

---------

为了使贴出来的代码具有完成性和尽量的简单性, 把以前的代码改写了一下, 现在的代码是控制台程序,

在程序体中对数据库访问代码作了简单的调用.

---------

今天重新看了一遍代码,发现一个问题,就是 程序入口里的变量 QueryResult 所使用过的对象都没有释放!!!

--date=2019-09-11

---------

数据访问单元的代码:

  1 unit uDBAccesser;
  2 
  3 interface
  4 
  5 uses
  6   System.Generics.Collections, Data.Win.ADODB;
  7 
  8 
  9 type TTAbleInfo = record
 10   DataSource : String;
 11   DbName     : String;
 12   Username   : String;
 13   Password   : String;
 14   Name       : String;
 15   IntCol     : String;
 16   TxtCol     : String;
 17 end;
 18 
 19 type TEntity = record
 20   SomeInt : Integer;
 21   SomeTxt : String;
 22 end;
 23 
 24 type TDBAccesser = class
 25   private
 26     FConn : TADOConnection;
 27 
 28     function Query( const ASql : String; const AParams : TDictionary<String, Variant>) : TList<TEntity>;
 29     // 广泛含义的更新
 30     function Update(Const ASql : String; const AParams : TDictionary<String, Variant>) : Boolean; overload;
 31   public
 32     constructor Create();
 33     destructor  Destroy(); override;
 34 
 35     function QueryAll() : TList<TEntity>;
 36     function QueryByInt(const AInt : Integer) : TList<TEntity>;
 37     function QueryByTxt(const ATxt : String ) : TList<TEntity>;
 38     function InsertOne(const AEntity : TEntity) : Boolean;
 39     function Delete(const AEntity : TEntity) : Boolean;
 40     // 狭义的更新
 41     function Update(const AOldValue : TEntity; const ANewValue : TEntity) : Boolean; overload;
 42 end;
 43 
 44 
 45 var
 46   TableInfo : TTableInfo;
 47 
 48 implementation
 49 
 50 uses
 51   System.SysUtils, System.Variants, Winapi.ActiveX;
 52 
 53 
 54 constructor TDBAccesser.Create();
 55 const  // MS SQL
 56   LConnStrFormat : String = 'provider=SQLOLEDB.1;password=%s;User ID=%s;'
 57                           + 'Initial CataLog=%s;Data source=%s;';
 58 var
 59   LConnStr : String;
 60 begin
 61   try
 62     LConnStr := Format(LConnStrFormat, [TableInfo.Password, TableInfo.Username,
 63                                         TableInfo.DbName, TableInfo.DataSource]);
 64 
 65     Self.FConn := TADOConnection.Create(nil);
 66     Self.FConn.ConnectionString := LConnStr;
 67     Self.FConn.LoginPrompt := False;
 68     Self.FConn.Connected   := True;
 69   except
 70     on Err : Exception do begin
 71       FreeAndNil(Self.FConn);
 72       WriteLn('Error on create DBAccesser: ' + Err.Message);
 73     end;
 74   end;
 75 end;
 76 
 77 destructor TDBAccesser.Destroy;
 78 begin
 79   FreeAndNil(Self.FConn);
 80 end;
 81 
 82 
 83 function TDBAccesser.Query(const ASql: string; const AParams: TDictionary<System.string,System.Variant>) : TList<TEntity>;
 84 var
 85   LDataSet : TADODataSet;
 86   LRow : TEntity;
 87   LKey : String;
 88 begin
 89   LDataSet := nil;
 90   try
 91     LDataSet := TADODataSet.Create(nil);
 92     LDataSet.Connection  := Self.FConn;
 93     LDataSet.CommandText := ASql;
 94 
 95     // 我印象有篇文章说这句必须要有, 但不写也没发现问题
 96     LDataSet.Parameters.ParseSQL(LDataSet.CommandText, True);
 97     if (AParams <> nil) then begin
 98       for LKey in AParams.Keys do begin
 99         LDataSet.Parameters.ParamByName(LKey).Value := AParams.Items[LKey];
100       end;
101     end;
102 
103     LDataSet.Open;
104     LDataSet.First;
105 
106     Result := TList<TEntity>.Create();
107     while not LDataSet.Eof do begin
108       LRow.SomeInt := LDataSet.FieldByName(TableInfo.IntCol).AsInteger; // 也可以这种格式 LDataSet.Fields[0].AsBoolean;
109       LRow.SomeTxt := LDataSet.FieldByName(TableInfo.TxtCol).AsString;
110 
111       Result.Add(LRow);
112 
113       LDataSet.Next;
114     end;
115   finally
116     FreeAndNil(LDataSet);
117   end;
118 end;
119 
120 function TDBAccesser.Update(Const ASql : String; const AParams : TDictionary<String, Variant>) : Boolean;
121 var
122   LCmd : TADOCommand;
123   LKey : String;
124   LRowsAffected : Integer;
125 begin
126   Result := False;
127   LCmd := nil;
128   try
129     LCmd := TADOCommand.Create(nil);
130     LCmd.Connection  := Self.FConn;
131     LCmd.CommandText := ASql;
132 
133     LCmd.Parameters.ParseSQL(LCmd.CommandText, True);
134 
135     if (AParams <> nil) then begin
136       for LKey in AParams.Keys do begin
137         LCmd.Parameters.ParamByName(LKey).Value := AParams.Items[LKey];
138       end;
139     end;
140 
141     // 也可以直接在 EmptyParam 的位置直接写 [Param1, Param2, ...] 格式的内容,
142     // 而不使用上面的 Parameters,两者不能同时使用,
143     // 但具体什么情况我也忘了,相应代码也找不到了,要想知道真实情况,还得再动手去摸索
144     LCmd.Execute(LRowsAffected, EmptyParam);
145 
146     if (LRowsAffected > 0) then begin
147       Result := True;
148     end
149     else begin
150       Result := False;
151     end;
152   finally
153     FreeAndNil(LCmd);
154   end;
155 end;
156 
157 
158 function TDBAccesser.QueryAll() : TList<TEntity>;
159 const
160   LSqlFormat : String = 'SELECT %s, %s FROM %s';
161 var
162   LSql : String;
163 begin
164   LSql := Format(LSqlFormat, [TableInfo.TxtCol, TableInfo.IntCol, TableInfo.Name]);
165 
166   Result := Self.Query(LSql, nil);
167 end;
168 
169 function TDBAccesser.QueryByInt(const AInt: Integer) : TList<TEntity>;
170 const
171   LSqlFormat : String = 'SELECT %s, %s FROM %s WHERE %s = :$Int ';
172 var
173   LSql : String;
174   LParams : TDictionary<String, Variant>;
175 begin
176   LParams := TDictionary<String, Variant>.Create();
177   try
178     LSql := Format(LSqlFormat, [TableInfo.TxtCol, TableInfo.IntCol,
179                                 TableInfo.Name, TableInfo.IntCol]);
180 
181     LParams.Add('$Int', AInt);
182 
183     Result := Self.Query(LSql, LParams);
184   finally
185     FreeAndNil(LParams);
186   end;
187 end;
188 
189 function TDBAccesser.QueryByTxt(const ATxt: String) : TList<TEntity>;
190 const
191   LSqlFormat : String = 'SELECT %s, %s FROM %s WHERE %s = :$Txt ';
192 var
193   LSql : String;
194   LParams : TDictionary<String, Variant>;
195 begin
196   LParams := TDictionary<String, Variant>.Create();
197   try
198     LSql := Format(LSqlFormat, [TableInfo.TxtCol, TableInfo.IntCol,
199                                 TableInfo.Name, TableInfo.TxtCol]);
200 
201     LParams.Add('$Txt', ATxt);
202 
203     Result := Self.Query(LSql, LParams);
204   finally
205     FreeAndNil(LParams);
206   end;
207 end;
208 
209 function TDBAccesser.InsertOne(const AEntity: TEntity) : Boolean;
210 const
211   LSqlFormat : String = 'INSERT INTO %s (%s, %s) '
212                       + 'VALUES (:$Txt, :$Int) ';
213 var
214   LSql : String;
215   LParams : TDictionary<String, Variant>;
216 begin
217   LParams := TDictionary<String, Variant>.Create();
218   try
219     LSql := Format(LSqlFormat, [TableInfo.Name, TableInfo.TxtCol, TableInfo.IntCol]);
220 
221     LParams.Add('$Txt', AEntity.SomeTxt);
222     LParams.Add('$Int', AEntity.SomeInt);
223 
224     Result := Self.Update(LSql, LParams);
225   finally
226     FreeAndNil(LParams);
227   end;
228 end;
229 
230 function TDBAccesser.Delete(const AEntity: TEntity) : Boolean;
231 const
232   LSqlFormat : String = 'DELETE FROM %s '
233                       + 'WHERE %s = :$Txt AND %s = :$Int ';
234 var
235   LSql : String;
236   LParams : TDictionary<String, Variant>;
237 begin
238   LParams := TDictionary<String, Variant>.Create();
239   try
240     LSql := Format(LSqlFormat, [TableInfo.Name, TableInfo.TxtCol, TableInfo.IntCol]);
241 
242     LParams.Add('$Txt', AEntity.SomeTxt);
243     LParams.Add('$Int', AEntity.SomeInt);
244 
245     Result := Self.Update(LSql, LParams);
246   finally
247     FreeAndNil(LParams);
248   end;
249 end;
250 
251 function TDBAccesser.Update(const AOldValue: TEntity; const ANewValue: TEntity) : Boolean;
252 const
253   LSqlFormat : String = 'UPDATE %s '
254                       + 'SET %s = :$TxtVal, %s = :$IntVal '
255                       + 'WHERE %s = :$OldTxtVal AND %s = :$OldIntVal ';
256 var
257   LSql : String;
258   LParams : TDictionary<String, Variant>;
259 begin
260   LParams := TDictionary<String, Variant>.Create();
261   try
262     LSql := Format(LSqlFormat, [TableInfo.Name,
263                                 TableInfo.TxtCol, TableInfo.IntCol,
264                                 TableInfo.TxtCol, TableInfo.IntCol]);
265 
266     LParams.Add('$TxtVal', ANewValue.SomeTxt);
267     LParams.Add('$IntVal', ANewValue.SomeInt);
268 
269     LParams.Add('$OldTxtVal', AOldValue.SomeTxt);
270     LParams.Add('$OldIntVal', AOldValue.SomeInt);
271 
272     Result := Self.Update(LSql, LParams);
273   finally
274     FreeAndNil(LParams);
275   end;
276 end;
277 
278 
279 initialization
280   TableInfo.DataSource := '.';
281   TableInfo.DbName     := 'simpleTestByX';
282   TableInfo.Username   := 'sa';
283   TableInfo.Password   := '123456';
284   TableInfo.Name       := 'tab_simple_test';
285   TableInfo.IntCol     := 'some_int';
286   TableInfo.TxtCol     := 'some_txt';
287 
288   CoInitialize(nil);
289 
290 finalization
291   CoUninitialize();
292 
293 
294 end.

 

控制台程序入口代码,对上面的单元进行简单的调用:

  1 program ProjectParameterizedSql;
  2 
  3 {$APPTYPE CONSOLE}
  4 
  5 {$R *.res}
  6 
  7 uses
  8   System.SysUtils,
  9   System.Generics.Collections,
 10   uDBAccesser in 'uDBAccesser.pas';
 11 
 12 
 13 function FormatEntity(AEntity : TEntity) : String;
 14 begin
 15   Result := Format(' SomeInt = %d, SomeTxt = %s ', [AEntity.SomeInt, AEntity.SomeTxt]);
 16 end;
 17 
 18 
 19 var
 20   DBAccesser      : TDBAccesser;
 21   EntityQuery     : TEntity;
 22   EntityInsert    : TEntity;
 23   EntityDelete    : TEntity;
 24   EntityUpdateNew : TEntity;
 25   EntityUpdateOld : TEntity;
 26   EntityCommon    : TEntity;
 27   QueryResult     : TList<TEntity>;
 28 begin
 29   try
 30     DBAccesser := TDBAccesser.Create();
 31     try
 32       WriteLn('1) insert one: ');
 33 
 34       EntityInsert.SomeInt := 1;
 35       EntityInsert.SomeTxt := 'Hello';
 36       WriteLn('  entity = ', FormatEntity(EntityInsert));
 37 
 38       WriteLn('  insert success? ', DBAccesser.InsertOne(EntityInsert));
 39       WriteLn('----------------');
 40 
 41       WriteLn('2) query all: ');
 42 
 43       QueryResult := DBAccesser.QueryAll();
 44 
 45       WriteLn('  total = ', QueryResult.Count);
 46       for EntityCommon in QueryResult do begin
 47         WriteLn('  ', FormatEntity(EntityCommon));
 48       end;
 49       WriteLn('----------------');
 50 
 51       WriteLn('3) update: ');
 52 
 53       EntityUpdateOld := EntityInsert;
 54       EntityUpdateNew.SomeInt := 2;
 55       EntityUpdateNew.SomeTxt := 'World';
 56 
 57       WriteLn('  old : ', FormatEntity(EntityUpdateOld));
 58       WriteLn('  new : ', FormatEntity(EntityUpdateNew));
 59 
 60       WriteLn('  update success? ', DBAccesser.Update(EntityUpdateOld, EntityUpdateNew));
 61       WriteLn('----------------');
 62 
 63       WriteLn('4) query by int:');
 64 
 65       EntityQuery := EntityUpdateNew;
 66       WriteLn('  int = ', EntityQuery.SomeInt);
 67 
 68       QueryResult := DBAccesser.QueryByInt(EntityQuery.SomeInt);
 69 
 70       WriteLn('  total : ', QueryResult.Count);
 71       for EntityCommon in QueryResult do begin
 72         WriteLn('  ', FormatEntity(EntityCommon));
 73       end;
 74       WriteLn('----------------');
 75 
 76       WriteLn('5) query by txt:');
 77 
 78       EntityQuery := EntityUpdateNew;
 79       WriteLn('  txt = ', EntityQuery.SomeTxt);
 80 
 81       QueryResult := DBAccesser.QueryByTxt(EntityQuery.SomeTxt);
 82 
 83       WriteLn('  total : ', QueryResult.Count);
 84       for EntityCommon in QueryResult do begin
 85         WriteLn('  ', FormatEntity(EntityCommon));
 86       end;
 87       WriteLn('----------------');
 88 
 89       WriteLn('6) delete:');
 90 
 91       EntityDelete := EntityUpdateNew;
 92       WriteLn('  entity = ', FormatEntity(EntityDelete));
 93 
 94       WriteLn('  delete success? ', DBAccesser.Delete(EntityDelete));
 95       WriteLn('----------------');
 96 
 97       WriteLn('7) query all: ');
 98 
 99       QueryResult := DBAccesser.QueryAll();
100       WriteLn('  total : ', QueryResult.Count);
101       for EntityCommon in QueryResult do begin
102         WriteLn('  ', FormatEntity(EntityCommon));
103       end;
104       WriteLn('----------------');
105 
106       WriteLn('--- THE END ---');
107     finally
108       FreeAndNil(DBAccesser);
109     end;
110   except
111     on E: Exception do
112       Writeln(E.ClassName, ': ', E.Message);
113   end;
114   ReadLn;
115 end.

 

--------- THE END ---------

转载于:https://www.cnblogs.com/shadow-abyss/p/11126900.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/424295.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

20 Valid Parentheses

1 题目理解 输入&#xff1a;一个字符串s&#xff0c;只包含( ) { } [ ]这六种字符。 输出&#xff1a;字符串是否有效 规则&#xff1a;一个有效的字符串需要括号对应匹配&#xff0c;并且要左括号在前。 举例&#xff1a; 1 输入s"()"&#xff0c;输出true 2 Inpu…

SQL select 语法(转)

SQL 里面最常用的命令是 SELECT 语句&#xff0c;用于检索数据。语法是&#xff1a; SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]* | expression [ AS output_name ] [, ...][ INTO [ TEMPORARY | TEMP ] [ TABLE ] new_table ][ FROM from_item [, ...] ][ WHER…

spring mvc学习(9):路径参数

目录结构 web.xml <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xmlns"http://java.sun.com/xml/ns/javaee" xsi:schemaLocation"http://java.sun.com/xml…

mysql函数(五.流程控制函数)

流程控制函数 1.IF(expr1,expr2,expr3) 判断条件的正误&#xff0c;返回对应值 (1)判断条件的正返回expr2&#xff0c;否则返回expr3 select IF(10>5,大于,小于) as result; 结果&#xff1a;大于 2.IFNULL(expr1,expr2) 判断值是否为空 (1)判断值为空返回expr2&#x…

扩展String类

因为.Net Framework中的String类是封闭的&#xff0c;所以我们不能从它进行派生来扩展它的功能。 虽然String类已经提供了很多有用的方法来让我们进行字符串的处理和操作&#xff0c;但是有时候一些特殊的的要求还是不能能到满足。 一个例子就是&#xff1a;假如有一个因为句…

150 Evaluate Reverse Polish

1题目理解 输入&#xff1a;一个字符串数组。这个字符串数组表示算数运算的逆波兰表示法。一般算数表示方法是21&#xff0c;逆波兰表示是2 1 。 输出&#xff1a;一个int值。 Example 1: Input: [“2”, “1”, “”, “3”, “*”] Output: 9 Explanation: ((2 1) * 3) …

第八十七期:爬了知乎“沙雕问题”,笑死个人!

这两天偶然上网的时候&#xff0c;被知乎上一个名为“玉皇大帝住在平流层还是对流层”的问题吸引。 作者&#xff1a;数据森麟 这两天偶然上网的时候&#xff0c;被知乎上一个名为“玉皇大帝住在平流层还是对流层”的问题吸引。 图片来自 Pexels 本以为只是小打小闹&#xf…

django的url控制系统

无命名分组 &#xff08;\d{4}&#xff09; 有命名分组 &#xff08;&#xff1f;P<name>\d{4}&#xff09; 一个视图做两件事&#xff0c;提交方法不一样&#xff08;if 判断&#xff09; form action"/register/" django默认添加了当前面IP和端口 url别名…

641. Design Circular Deque

1 题目理解 要求设计一个双端循环队列。这个队列能支持以下操作&#xff1a; MyCircularDeque(k): Constructor, set the size of the deque to be k. insertFront(): Adds an item at the front of Deque. Return true if the operation is successful. insertLast(): Adds a…

QQ技术攻略-原来隐藏着这么多秘密(上)

一、将您的QQ的在线状态发布在互联网上将您的QQ的在线状态发布在互联网上&#xff0c;不用加好友也可以聊天.将您的QQ/TM的在线状态发布在互联网上&#xff1b;点击 QQ在线&#xff0c;不用加好友也可以聊天&#xff1b;寻找商机&#xff0c;广交朋友&#xff0c;"互动状态…

第八十八期:4000万程序员最爱开源项目和编程语言排名出炉!

今天&#xff0c;全球最大开发者社区GitHub重磅发布2019年度报告&#xff0c;透露了一个数据&#xff1a;GitHub目前在全球已有超过4000万开发者用户&#xff0c;其中80%来自美国之外的地区。 作者&#xff1a;小芹、亮亮 全球最大开发者社区GitHub今天重磅发布2019年度报告&…

Java2实用教程(第二版)程序代码——第十四章 Component类的常用方法

1//例子12import java.applet.*;import java.awt.*;3import java.awt.event.*;4import javax.swing.JTextArea;5publicclassExample14_1 extends Applet implements ItemListener6{ List list ; 7 JTextArea text; 8 public void init() 9 { listnew List(6,false…

239. Sliding Window Maximum

文章目录1理解题目2 思路2.1暴力求解2.2双端队列1理解题目 输入&#xff1a;整数数组nums&#xff0c;滑动窗口大小k 输出&#xff1a;整数数组 规则&#xff1a;在一个窗口内只能看到k个数&#xff0c;找一个最大的数&#xff0c;添加到返回数组中。每次滑动向右滑动一步。 …

第八十九期:还在手动盖楼领喵币?双十一这群开发者竟然如此「作弊」

开发者构建了一个脚本以自动逛双十一会场&#xff0c;让使用者轻松完成各种领币任务&#xff0c;同时还能解放双手。 作者&#xff1a;Synced 每年的 11 月份&#xff0c;总觉得有些硝烟弥漫。好在淘宝双十一领喵币&#xff0c;也已经有了自动化脚本。 感觉还未从去年双十一…

Serverless简介

说起当前最火的技术&#xff0c;除了最新的区块链&#xff0c;AI&#xff0c;还有一个不得不提的概念是Serverless。Serverless作为一种新型的互联网架构直接或间接推动了云计算的发展&#xff0c;从AWS Lambda到阿里云函数计算&#xff0c;Serverless一路高歌&#xff0c;同时…

使用matlab工具研究神经网络的简单过程(网络和数据下载)

本人在神经网络研究中是个新手的新手&#xff0c;使用matlab gui工具能够让我们这些小菜也可以研究这些复杂的问题。 在matlab中输入“nntool”&#xff0c;这样就可以出来gui了哈哈。然后按照提示输入&#xff1a;输入数据&#xff0c;目标数据&#xff0c;网络的设置。自然也…

第九十期:哪种人是软件设计中的稀缺型人才?

好的系统架构离不开好的接口设计&#xff0c;因此&#xff0c;真正懂接口设计的人往往是软件设计队伍中的稀缺型人才。 作者&#xff1a;从码农到工匠 好的系统架构离不开好的接口设计&#xff0c;因此&#xff0c;真正懂接口设计的人往往是软件设计队伍中的稀缺型人才。 为什…

151. Reverse Words in a String

1 题目理解 输入&#xff1a;一个字符串s 规则&#xff1a;一个单词是一串非空字符组成的。单词之间用空格分隔。 输出&#xff1a;将字符串按照单词反转字符串。多余的空格只保留一个。 Example 1: Input: s “the sky is blue” Output: “blue is sky the” Example 2: …

C语言输入字符和字符串

C语言有多个函数可以从键盘获得用户输入&#xff0c;它们分别是&#xff1a; scanf()&#xff1a;和 printf() 类似&#xff0c;scanf() 可以输入多种类型的数据。getchar()、getche()、getch()&#xff1a;这三个函数都用于输入单个字符。gets()&#xff1a;获取一行数据&…

收集一些正则表达式

匹配中文字符的正则表达式&#xff1a; [\u4e00-\u9fa5] 匹配双字节字符(包括汉字在内)&#xff1a;[^\x00-\xff] 应用&#xff1a;计算字符串的长度&#xff08;一个双字节字符长度计2&#xff0c;ASCII字符计1&#xff09; String.prototype.lenfunction(){return this.re…