如何自动拼接 Update语句,仅Update已修改的字段

如何自动拼接 Update语句,仅Update已修改的字段,第1张

例如使用update user set username='001', nickname='Tom', age=18 where id =

1语句更新username、nickname或age字段的值。假设,我们只修改了username,并没有修改nickname和age,那么上面的

sql就显得多余了,改成update user set username='001' where id =

1才算完美,即哪些字段发生了变化就更新哪些字段。

此外,SQL Server数据库中有触发器,可监控到字段值的变更,例如在表user上创建触发器

create trigger [dbo][tr_user_update]

on [dbo][user]

After

update

as

declare @id int;

select @id = id from inserted;

if update(nickname) begin

--some code

end;

如果使用update user set username='001', nickname='Tom', age=18 where id = 1语句,即便nickname和age的值与数据库中完全一样,也会触发 some code,但这并不是我们期望的。

所以执行update更新前,有必要检查哪些字段需发生了修改,尤其是需要记录表变更历史的情形。本例中,笔者使用SystemReflectionPropertyInfo和DataRow检查发生更新的字段,并拼接要更新的Update SQL语句。

首先,按照表user创建Usercs类

class User

{

// 参照用户表User的字段定义属性

// 不包括系统字段

// 仅包括用户会修改的字段

// 属性名必须和字段名一致

public string UserName { get; set; }

public string NickName { get; set; }

public string Password { get; set; }

public string Email { get; set; }

public string Phone { get; set; }

public int Age { get; set; }

}

其次,创建赋值函数InitEntity(DataRow, Obj)

public static Obj InitEntity<Obj>(SystemDataDataRow row, Obj entity) where Obj : new()

{

if (entity == null)

entity = new Obj();

// 取得entity的类型

Type type = typeof(Obj);

// 取得entity的属性

SystemReflectionPropertyInfo[] props = typeGetProperties();

// 遍历entity属性集合,按照属性类型给其赋值。通过entity属性名从row中取得对应的值。

foreach (SystemReflectionPropertyInfo prop in props)

{

if (propPropertyTypeFullNameEquals("SystemInt32"))

{

propSetValue(entity

, ConvertChangeType(MyFuncLibdtv(row, propName, "0")

, propPropertyType), null);

}

else if (propPropertyTypeFullNameEquals("SystemDecimal"))

{

propSetValue(entity

, ConvertChangeType(MyFuncLibdtv(row, propName, "0")

, propPropertyType), null);

}

else if (propPropertyTypeFullNameEquals("SystemDouble"))

{

propSetValue(entity

, ConvertChangeType(MyFuncLibdtv(row, propName, "0")

, propPropertyType), null);

}

else if (propPropertyTypeFullNameEquals("SystemBoolean"))

{

propSetValue(entity

, ConvertChangeType(MyFuncLibdtv(row, propName, "false")

, propPropertyType), null);

}

else if (propPropertyTypeFullNameEquals("SystemDateTime"))

{

if (MyFuncLibdtv(row, propName, null) != null)

{

propSetValue(entity

, ConvertChangeType(MyFuncLibdtv(row, propName, null)

, propPropertyType), null);

}

}

else

{

propSetValue(entity

, MyFuncLibdtv(row, propName, stringEmpty), null);

}

}

return entity;

}

显示用户数据时,将数据保存在一个DataTable dt中

private void Form1_Load(object sender, EventArgs e)

{

// 初始化表时,读取数据

SqlConnection conn = new SqlConnection();

connConnectionString = "";

connOpen();

SqlDataAdapter adapter = new SqlDataAdapter();

adapterSelectCommandCommandText = "select from user where id = 1";

adapterFill(dt);

adapter = null;

connClose();

}

修改数据后,将变更存入dt的第一条记录newRow中。保存数据前从数据库中读取记录存入oldRow,然后比较oldRow和newRow差异,遇到差异时拼接Update SQL语句。

private void btnSave_Click(object sender, EventArgs e)

{

// 理论上只有一条记录值

if (dtRowsCount > 0)

{

// 模拟数据修改,直接修改dtRows[0]

#region update row

dtRows[0]["UserName"] = "001";

dtRows[0]["NickName"] = "Tom";

dtRows[0]["Password"] = "123456";

#endregion

// 打开数据库

SqlConnection conn = new SqlConnection();

connConnectionString = "";

connOpen();

// 修改前读取数据库中的记录

DataTable dtTemp = new DataTable();

SqlDataAdapter adapter = new SqlDataAdapter();

adapterSelectCommandCommandText = "select from user where id = 1";

adapterFill(dtTemp);

DataRow oldRow = dtTempRows[0];

adapter = null;

// 当前数据库中的值

User oldItem = MyFuncLibInitEntity(oldRow, new User());

// 可能已经发生修改的值

User newItem = MyFuncLibInitEntity(dtRows[0], new User());

// 标识当前记录是否发生了修改

bool amended = false;

// Update Sql

StringBuilder sql = new StringBuilder();

sqlAppendLine("update user set modifiedDate = getDate()");

// 定义Update Command

SqlCommand comdUpdate = new SqlCommand();

// 遍历User类属性

SystemReflectionPropertyInfo[] props = typeof(User)GetProperties();

foreach (SystemReflectionPropertyInfo prop in props)

{

// 排除id等系统字段

if (!propNameEquals("id"))

{

// 仅当值发生修改时才拼接SQL语句

if (!propGetValue(oldItem, null)Equals(propGetValue(newItem, null)))

{

// 拼接Update语句

sqlAppendLine(stringFormat(",[{0}] = @{0}", propName));

// 同时添加参数

comdUpdateParametersAddWithValue(

stringFormat("@{0}", propName)

, propGetValue(newItem, null)ToString());

// 只要有一个字段值发生了变化,就设置amended = true

amended = true;

// 此处可插入日志代码,用于对当前表变更历史的记录

}

}

}

if (amended)

{

// 执行拼接的Update Sql

comdUpdateCommandText = sqlToString();

comdUpdateConnection = conn;

comdUpdateExecuteNonQuery();

}

// 关闭SQL连接

connClose();

}

}

(一)数据备份

为了能在系统出错后重建数据库,对系统上所有文件周期性地做备份是十分重要的。数据可能受到各种外来因素的影响而破坏其完整性甚至崩溃,这时利用数据库的备份来进行恢复就显得尤为重要。一般采用硬件防护、定期热备份、异地备份3种方式来确保数据备份的安全性。

(1)硬件防护

数据库是一个系统的核心,为了保证系统运行的高效性和可靠性,从硬件的角度必须选择性能优越、稳定可靠的服务器,如采用HP ML530G2服务器,对服务器的硬盘通过RAID5技术,把3块硬盘做成一块逻辑硬盘,以提高当硬盘硬件出现故障时数据的安全性。

(2)定期热备份

系统可基于SQL Server 2000中的备份和还原组件实现整个数据库周期性地备份与还原,可以将数据库转换成MDF格式的数据,而且该格式可以方便快捷地倒回到原来的系统中。真正做到系统能在数据损坏、丢失等情况下将备份倒回,实现数据恢复。

另外,做好异地备份。

(二)系统完善

当软件开发完成并进入运行维护阶段,在该阶段软件完善主要考虑以下几个方面。

(1)改正性维护

其目的是为了纠正运行阶段发现的软件性能上的缺陷、排除应用中的误用以及软件 *** 作习惯。把“BUG”减少到最少的程度,保证系统长期正常运转。

(2)适应性维护

随着计算机技术的发展,当软件的外部环境或者数据环境发生变化时,用户往往会对软件提出新的功能和性能需求,为了满足这些需求,需要修改或再开发软件。

(3)预防性维护

预防性维护的目的是为了提高软件的可维护性和可靠性等,在发生意外的软、硬件故障等情况下,能够很好地处理并给出错误报告,并且能够得到及时恢复,减少不必要的损失。

(三)数据更新

浙江省农业地质环境数据库的数据更新是一个难题。农业地质环境调查是一项长期公益性工作,需要对农业地质环境进行定期监测和分析,土壤、地下水、农产品监测数据及相关地图数据均要求导入到AGEIS系统数据库中,因此作为浙江省农业地质环境数据管理平台,需要提供能实现数据更新的接口。数据更新主要包括图形数据、属性数据、调查数据的更新3部分。浙江省农业地质环境信息系统是以数据管理和应用为目的,图层数据的更新功能相对薄弱,如果要复杂的编辑还需第三方软件进行辅助解决。本次仅强调属性数据和调查数据的更新。

属性数据的更新有2种情况,数据库字段的变更和数据库属性内容的变更。对于数据库字段的变更,可以直接更改数据库结构,在保证关键字段不变的前提下,任何的改变都不影响系统的正常运行。数据库内容的变化,相对而言比较简单,直接修改字段内容。

调查数据(包括定期监测数据)的更新包括添加、修改及删除等。根据项目的特点,调查数据一般以点的形式存在,系统提供了2种方式实现调查数据的更新,一是将调查数据表转换成空间数据图层,但数据调查表的格式应按《浙江省农业地质环境数据库图层及属性文件格式要求》中相关要求进行编制,系统可以直接读取Access格式的数据;另一种就是借用第三方软件,将数据表转换成以度为单位的ShapeFiles文件格式(也可为Arc/Info或DXF格式),通过系统维护子系统的数据导入功能即可。

监控数据备份恢复完成进度(EXPDP/IMPDP/RMAN)

一、查看EXPDP/IMPDP的进度

1 两个视图

当你当如导出的时候,如果数据量比较大,中途有些人会着急,不免想看看进度如何,利用两个视图就可以看:

DBA_DATAPUBMP_JOBS和DBA_DATAPUMP_SESSIONS视图 

col owner_name for a10 

col job_name for a20 

col operation for a10 

col job_mode for a10 

col state for a20 

col degree for a10 

col  ATTACHED_SESSIONS for a30 

col DATAPUMP_SESSIONS for a30 

set linesize 200

格式化只是为了好看,也可以不用,直接用PL/SQL DEVELOPER图形工具。

可以使用DBA_DATAPUBMP_JOBS和DBA_DATAPUMP_SESSIONS视图来显示数据泵取作业的信息。

select  from DBA_DATAPUBMP_JOBS; 

select  from DBA_DATAPUMP_SESSIONS;   

select sid,serial# from v$session s,dba_datapump_sessions d where ssaddr=dsaddr;

补充一下,前面的sql命令行格式化有点问题,number型的字段应该用9999xxx(多个9) 而不是axx,否则会出现一串串的#。

2 attach参数

1)查看任务进度

当你使用crontab后台任务运行导入导出任务的时候,想查看任务进度,该参数很有用,可以让你再次连接到已经断开的会话中,再次接管导出或导入的任务,当然你得先用前面2个视图查到jobname。

2)中途想停止crontab后台任务

此时,该参数非常好用。因为你不这样做,就得杀进程,而那么多进程,通常都会出错,如此暴利的杀进程方式,强烈滴不推荐。

举例:

假如之前后台任务的脚本中,有类似命令:

expdp system/xxx   DIRECTORY=DATA_PUMP_DIR2  parallel=32  DUMPFILE=xxxx-%Udmp 

ATTACH参数解释:将你的数据泵取客户机会话加入到一个运行的作业中,并使你进行交互方式。此参数只能与用户名/密码组合一起使用。

 

此时你可以使用如下命令重新连接任务,并达到提前终止任务的目的:

 

expdp system/xxx   attach=lurouexp

连接进去之后再执行help命令可以查到停止任务的命令,这里就不列出来了

3 longops视图

另也可以通过v$session_longops视图来监控长期运行的会话。

 

4通过语句查看impdp进度SELECT   atablespace_name,          

ROUND (atotal_size) "total_size(MB)",          

ROUND (atotal_size) - ROUND (bfree_size, 3) "used_size(MB)",          

ROUND (bfree_size, 3) "free_size(MB)",          

ROUND (bfree_size / total_size  100, 2) || '%' free_rate   

FROM   

(  

SELECT   

tablespace_name, SUM (bytes) / 1024 / 1024 total_size               

FROM   dba_data_files           

GROUP BY   

tablespace_name) a,          

(  

SELECT   

tablespace_name, SUM (bytes) / 1024 / 1024 free_size               

FROM   dba_free_space           

GROUP BY   

tablespace_name) b  

WHERE   

atablespace_name = btablespace_name(+);

二、查看RMAN备份进度

另外,查看rman的备份进度,可以用如下语句,记录备忘。

SELECT SID,OPNAME, SERIAL#, CONTEXT, SOFAR, TOTALWORK, ROUND(SOFAR/TOTALWORK100,2) "%_COMPLETE"

FROM V$SESSION_LONGOPS WHERE OPNAME LIKE 'RMAN%'AND OPNAME NOT LIKE '%aggregate%'AND TOTALWORK != 0 AND SOFAR <> TOTALWORK 

order by "%_COMPLETE" desc

在使用一些流行的Web框架(如Django、Ruby on Rails等)进行应用程序开发时,通常会使用一个工具来记录和管理数据库变更的文件,这个工具通常被称为“迁移(Migration)”。

在Django中,迁移是通过创建一个Python文件来实现的,其中包含一些数据库变更的指令,例如创建或删除表格,添加或删除字段等。当应用程序启动或执行migrate命令时,Django将根据这些迁移文件中的指令来同步数据库模式,确保数据库与应用程序代码的最新版本保持一致。

在Ruby on Rails中,类似的工具被称为“迁移(Migration)”或“数据库迁移(Database Migration)”,可以使用命令行工具生成迁移文件并执行迁移 *** 作。

总之,无论是哪个Web框架,迁移文件都旨在帮助开发人员轻松管理和维护应用程序和数据库之间的关系,避免了手动执行数据库变更 *** 作所带来的复杂性和错误。

默认是c盘,但在应用中由于数据库会随时间变大,因此建议用户自建数据库应放在一个空间足够大的硬盘中,我们一般系统安装在

c盘,数据放在其它盘中,如d盘等。还有数据自动备份不要与用户数据库在同一盘中。等等,它的一切在于你的安排和经验。

UPDATE [表名] SET [字段1] = 200,[字段2] = '字段值' WHERE [字段三] = 'HAIWA' 直接修改就好了,例:update user set name='binbin' where id=200;

以上就是关于如何自动拼接 Update语句,仅Update已修改的字段全部的内容,包括:如何自动拼接 Update语句,仅Update已修改的字段、系统维护与更新、如何监控oracle数据库的备份等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/10192116.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-06
下一篇 2023-05-06

发表评论

登录后才能评论

评论列表(0条)

保存