现在使用数据库来写存储过程,动不动参数就会用到xml ,当然罗,优势也很明显,参数相对固定,而且灵活,如果要修改或者什么的,中间接口层也不需要做变化,只需要修改封装的存储过程以及程序传参就ok了。

随着时间慢慢过,有时候就有一个存储过程,一个xml 来应对整个表的新增,修改,删除的情况了。而对于这个情况,我个人比较喜欢使用 Merge关键字来处理。但是如果表里面的列很多,那么复制黏贴啊之类的机械动作就会很多,而且没有什么价值。所以我就写了一个小脚本,应对了使用xml 来做表的增删改的作用

首先我先创建一个表

CREATE TABLE employee(
ID INT IDENTITY(1,1) PRIMARY KEY,
name NVARCHAR(50),
age INT,
birthdate DATE,
salary MONEY
)

然后我准备使用这个xml 来进行对应写入

DECLARE @employee XML='
<root>
<employee Action="1"> <!--这个Action 代表动作,1 新增 2 修改 3 删除 这样来控制比较灵活,不需要每次都一大段-->
<name>AAA</name>
<age>27</age>
<birthdate>1989-01-02</birthdate>
<salary>1200</salary>
</employee>
<employee Action="1">
<name>BBB</name>
<age>23</age>
<birthdate>1994-01-02</birthdate>
<salary>2200</salary>
</employee>
</root>
'

然后是生成的脚本。通常解析xml 会有2种的解析方法,一种是直接用openxml 来进行解析,一种是使用 xml.nodes 的函数进行取值,这里我两种都可以进行一个简单处理生成

 DECLARE @TableName VARCHAR(50) = 'employee',
@XMLType TINYINT = 1, --1 使用with 格式, 2 使用nodes 格式
@Path NVARCHAR(max) = 'root/employee',
@HasAction BIT = 1 --0 没有动作 1 包含动作 DECLARE @Columns NVARCHAR(MAX), --通用列的串
@FilterColumns NVARCHAR(max), --过滤外键,主键的列
@On NVARCHAR(100), --自动生成主键去匹配
@Sql NVARCHAR(MAX) SELECT @Columns = STUFF((
SELECT ',' + name
FROM sys.columns
WHERE object_id = OBJECT_ID(@TableName)
ORDER BY column_id
FOR XML PATH('')),1,1,''),
@FilterColumns = STUFF((
SELECT ',' + name
FROM sys.columns
WHERE object_id = OBJECT_ID(@TableName)
AND is_computed = 0
AND is_identity = 0
ORDER BY column_id
FOR XML PATH('')),1,1,''),
@On = STUFF((
SELECT 'AND TAR.' + c.name + ' = SOUR.' + c.name
FROM sys.indexes a
INNER JOIN sys.index_columns b ON a.object_id = b.object_id
INNER JOIN sys.columns c ON c.object_id = b.object_id AND b.column_id = c.column_id
WHERE a.object_id = OBJECT_ID(@TableName)
AND a.is_primary_key = 1),1,4,'') SELECT @Sql = ';WITH SOUR AS(
SELECT '+ CASE WHEN @XMLType = 1 THEN REPLACE(@Columns ,',',CHAR(10) + REPLICATE(CHAR(9),2) + ',')
WHEN @XMLType = 2 THEN STUFF((SELECT CHAR(10) + ',t.c.value(''(' + a.name + '/text())[1]'',''' + TYPE_NAME(user_type_id) + CASE WHEN a.system_type_id IN (167,175) THEN '(' + CASE WHEN a.max_length = -1 THEN 'max' ELSE RTRIM(a.max_length) END+ ')'
WHEN a.system_type_id IN (231,239) THEN '(' + CASE WHEN a.max_length = -1 THEN 'max' ELSE RTRIM(a.max_length/2) END + ')'
WHEN a.system_type_id IN (59,106,108) THEN '(' + RTRIM(a.max_length) + ',' + RTRIM(a.scale) + ')'
ELSE ''
END + ''') AS ' + a.name
FROM sys.columns a
WHERE object_id = OBJECT_ID(@TableName)
ORDER BY column_id
FOR XML PATH('')),1,2,'')
ELSE '' END
+ CASE WHEN @XMLType = 1 AND @HasAction = 1 THEN CHAR(10)+ REPLICATE(CHAR(9),2) + ',[Action]'
WHEN @XMLType = 2 AND @HasAction = 1 THEN CHAR(10)+ REPLICATE(CHAR(9),2) + ',t.c.value(''@Action'',''tinyint'') [Action]'
ELSE '' END
+ '
FROM ' + CASE @XMLType WHEN 1 THEN ' OPENXML(@XmlInt,''' + @Path + ''',3)
WITH(' + STUFF((SELECT CHAR(10)+ REPLICATE(CHAR(9),6) + ',' + a.name + ' ' + UPPER(b.name) + CASE WHEN a.system_type_id IN (167,175,231,239,108) THEN '(' + CASE WHEN a.max_length = -1 THEN 'MAX' ELSE RTRIM(a.max_length) END + ')'
WHEN a.system_type_id IN (59,106,108) THEN '(' + RTRIM(a.precision) + ',' + RTRIM(a.scale)+ ')'
ELSE '' END + ' ''' + a.name + ''''
FROM sys.columns a
INNER JOIN sys.systypes b ON a.system_type_id = b.xtype AND b.status = 0
WHERE object_id = OBJECT_ID(@TableName)
AND a.is_computed = 0
ORDER BY column_id
FOR XML PATH ('')
),1,8,'') +
+ CASE WHEN @HasAction = 1 THEN CHAR(10)+ REPLICATE(CHAR(9),6) + ',[Action] tinyint ''@Action'')' ELSE ')' END
WHEN 2 THEN ' @' + @TableName + '.nodes('''+@Path+''') as t(c)'
ELSE '' END
+ '),
TAR AS( SELECT ' + REPLACE(@Columns,',',CHAR(10) + REPLICATE(CHAR(9),2) + ',') + '
FROM ' + @TableName + ')
MERGE TAR
USING SOUR
ON '+@On+'
WHEN NOT MATCHED ' + CASE WHEN @HasAction = 1 THEN ' AND SOUR.[Action] = 1 ' ELSE '' END + '
THEN INSERT(' + @FilterColumns + ')' + CHAR(10) + REPLICATE(CHAR(9),5) + ' VALUES (SOUR.' + REPLACE(@FilterColumns,',',',SOUR.') + ')
WHEN MATCHED ' + CASE WHEN @HasAction = 1 THEN ' AND SOUR.[Action] = 2 ' ELSE '' END + ' THEN UPDATE SET '
+ STUFF(( SELECT ',' + CHAR(10) + REPLICATE(CHAR(9),5) + 'TAR.[' + name + ']= SOUR.[' + name + ']'
FROM sys.columns a
WHERE object_id = OBJECT_ID(@TableName)
AND is_computed = 0
AND is_identity = 0
AND NOT EXISTS(SELECT * FROM sys.foreign_key_columns WHERE parent_object_id = a.object_id AND parent_column_id = a.column_id)
ORDER BY column_id
FOR XML PATH('')
),1,6,'') + '
'+ CASE WHEN @HasAction = 1 THEN ' WHEN MATCHED AND SOUR.[Action] = 3 ' ELSE
'WHEN MATCHED BY SOURCE ' END + ' THEN Delete;'
PRINT @Sql

(因为偷懒,所以使用的openxml 里面的那个 sp_xml_preparedocument 这里我是没有写的)(*^__^*) 嘻嘻……

然后看下生成的情况,这个是使用xml.nodes 来生成的

 ;WITH SOUR AS(
SELECT t.c.value('(ID/text())[1]','int') AS ID
,t.c.value('(name/text())[1]','nvarchar(50)') AS name
,t.c.value('(age/text())[1]','int') AS age
,t.c.value('(birthdate/text())[1]','date') AS birthdate
,t.c.value('(salary/text())[1]','money') AS salary
,t.c.value('@Action','tinyint') [Action]
FROM @employee.nodes('root/employee') as t(c)),
TAR AS( SELECT ID
,name
,age
,birthdate
,salary
FROM employee)
MERGE TAR
USING SOUR
ON TAR.ID = SOUR.ID
WHEN NOT MATCHED AND SOUR.[Action] = 1
THEN INSERT(name,age,birthdate,salary)
VALUES (SOUR.name,SOUR.age,SOUR.birthdate,SOUR.salary)
WHEN MATCHED AND SOUR.[Action] = 2 THEN UPDATE SET TAR.[name]= SOUR.[name],
TAR.[age]= SOUR.[age],
TAR.[birthdate]= SOUR.[birthdate],
TAR.[salary]= SOUR.[salary]
WHEN MATCHED AND SOUR.[Action] = 3 THEN Delete;

xml.nodes

这个是使用openxml来生成的

;WITH SOUR AS(
SELECT ID
,name
,age
,birthdate
,salary
,[Action]
FROM OPENXML(@XmlInt,'root/employee',3)
WITH(ID INT 'ID'
,name NVARCHAR(100) 'name'
,age INT 'age'
,birthdate DATE 'birthdate'
,salary MONEY 'salary'
,[Action] tinyint '@Action')),
TAR AS( SELECT ID
,name
,age
,birthdate
,salary
FROM employee)
MERGE TAR
USING SOUR
ON TAR.ID = SOUR.ID
WHEN NOT MATCHED AND SOUR.[Action] = 1
THEN INSERT(name,age,birthdate,salary)
VALUES (SOUR.name,SOUR.age,SOUR.birthdate,SOUR.salary)
WHEN MATCHED AND SOUR.[Action] = 2 THEN UPDATE SET TAR.[name]= SOUR.[name],
TAR.[age]= SOUR.[age],
TAR.[birthdate]= SOUR.[birthdate],
TAR.[salary]= SOUR.[salary]
WHEN MATCHED AND SOUR.[Action] = 3 THEN Delete;

openxml

恩~然后就可放进去执行啦~~

这里只是一个很基本的用法。有几点要说明的

1、Xml的名称我默认和表名一致,有需要请改动

2、On的匹配模型我是使用主键来进行对应

其它如果有什么问题请告诉我补充~

写了一个常规性生成merge 的小脚本的更多相关文章

  1. 用c#写的一个局域网聊天客户端 类似小飞鸽

    用c#写的一个局域网聊天客户端 类似小飞鸽 摘自: http://www.cnblogs.com/yyl8781697/archive/2012/12/07/csharp-socket-udp.htm ...

  2. Python 写了一个批量生成文件夹和批量重命名的工具

    Python 写了一个批量生成文件夹和批量重命名的工具 目录 Python 写了一个批量生成文件夹和批量重命名的工具 演示 功能 1. 可以读取excel内容,使用excel单元格内容进行新建文件夹, ...

  3. 写了一个hiero中添加自定义Token的脚本

    Hiero自带Token往往不够用,shotname中自带版本号的情况下要升级版本会很麻烦,比如Shot_0001_v001这样一个序列名,要升级为Shot_0001_v002就必须把_v001之前的 ...

  4. 写了一个web使用向导的小插件

    运行效果: 引入插件: <link rel="stylesheet" href="ez-guide.css"> <script src=&qu ...

  5. 闲着无聊时写的一个调用天气 API 的小 Demo

    分为两个部分--调用以及实现,并且由于不想折腾,直接使用了 Console 来调用. 通过firefox直接调用 Main 入口,调用以及输出 调用部分没什么好说的,主要是针对 dynamic 类型的 ...

  6. 用Go语言写了一个电脑搜索文件的小东西

    package main import ( "bytes" "fmt" "os" "os/exec" "pat ...

  7. 用Python写了个下载快手视频的小脚本

    最近又重新拾起了,对python的热情. 贴个地址: https://github.com/d1y/lovepack/blob/master/kuaishou.py 前戏说明 因为我近乎癫狂的喜欢一个 ...

  8. 用python写的一个自动卸载python包的脚本

    import osplist=os.popen("pip list") # 执行windows cmd命令,获取所有包package列表,并获取返回结果到plist#跳过第1,2行 ...

  9. 基于c编写的关于随机生成四则运算的小程序

    基于http://www.cnblogs.com/HAOZHE/p/5276763.html改编写的关于随机生成四则运算的小程序 github源码和工程文件地址:https://github.com/ ...

随机推荐

  1. 一台电脑上的git同时使用两个github账户

    需求: 公司有github账号,自己有github账号,想在git上同时使用,两者互不干扰. 思路: 管理两个SHH key. 解决方案: 一.生成两个SSH key 为了举例方便,这里使用“one” ...

  2. Entity FrameWork 365日系列文章源码研究 (1)

    By KMSFan --  此系列的文章只作为自己的读书笔记,不纳入博客园首页. 总结的知识点: 1.DBContext 类 2.Attribute里的属性(NotNull) 3.DbContext实 ...

  3. ASP.NET实现微信功能(2)(服务号高级群发)

    前面写了一篇文章,关于微信的:http://www.cnblogs.com/kmsfan/p/4047097.html 今天打算来写本系列的第二批文章,服务号后台群发. 在写本篇文章之前,我们先来看看 ...

  4. MindMup 是一个开源的、在线的、简单的思维导图工具

    MindMup是一个开源.在线的思维导图工具:它有以下特点: 开源 在线 导图可存放在网站(公有,要是在不同的终端浏览的话需要记住导图的网址)或google driver(私有),无用户名密码 很方便 ...

  5. 企业 SOA 设计(1)–ESB 设计

    最近为公司完成了一个 ESB 的设计.下面简要说明一下具体的设计方案.   企业 SOA 整体方案 在前一篇<SOA.ESB.NServiceBus.云计算 总结>中说到,SOA 是面向服 ...

  6. Xenocode Postbuild 2010 for .NET 使用说明

    文章转载自网络 用法一: .导入要加密的dotNET程序或assembly文件(.dll/.exe) .选择第二个选项卡“Protect” .点击“Select Pattern” .选中所有“Obje ...

  7. 纪念品分组 2007年NOIP全国联赛普及组

    题目描述 元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作.为使得参加晚会的同学所获得的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品,并且每组纪念品的价格 ...

  8. UDS(ISO14229-2006) 汉译(No.6 应用层服务)

    6.1总览 应用层服务通常被当作诊断服务.应用层服务用于在基于客户端-服务器的系统(Client-Server base System)中执行一些功能,例如针对车载服务器(ECU)的检测.检查.监控和 ...

  9. ECharts(Enterprise Charts 商业产品图表库)初识

    一.简介 大数据时代,重新定义图表的时候到了,所以随之ECharts就随之出现了. ECharts(Enterprise Charts 商业产品图表库) 是基于Canvas的,纯Javascript ...

  10. .NET MVC 和 JAVA MVC有什么区别?

    两者的主要区别是编程语言的不同. 最典型的JAVA MVC就是JSP + servlet + javabean的模式.比较好的MVC,老牌的有Struts.Webwork.新兴的MVC 框架有Spri ...