写了一个常规性生成merge 的小脚本

现在使用数据库来写存储过程,动不动参数就会用到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 的函数进行取值,这里我两种都可以进行一个简单处理生成

 1 DECLARE @TableName VARCHAR(50) = ‘employee‘,
 2         @XMLType TINYINT = 1,  --1 使用with 格式, 2 使用nodes 格式
 3         @Path NVARCHAR(max) = ‘root/employee‘,
 4         @HasAction BIT = 1 --0 没有动作 1 包含动作
 5
 6 DECLARE @Columns NVARCHAR(MAX),    --通用列的串
 7         @FilterColumns NVARCHAR(max), --过滤外键,主键的列
 8         @On NVARCHAR(100), --自动生成主键去匹配
 9         @Sql NVARCHAR(MAX)
10
11 SELECT @Columns = STUFF((
12 SELECT ‘,‘ + name
13     FROM sys.columns
14         WHERE object_id = OBJECT_ID(@TableName)
15         ORDER BY column_id
16         FOR XML PATH(‘‘)),1,1,‘‘),
17 @FilterColumns = STUFF((
18 SELECT ‘,‘ + name
19     FROM sys.columns
20         WHERE object_id = OBJECT_ID(@TableName)
21            AND is_computed = 0
22               AND is_identity = 0
23         ORDER BY column_id
24         FOR XML PATH(‘‘)),1,1,‘‘),
25 @On = STUFF((
26 SELECT ‘AND TAR.‘ + c.name + ‘ = SOUR.‘ + c.name
27     FROM sys.indexes a
28         INNER JOIN sys.index_columns b ON a.object_id = b.object_id
29         INNER JOIN sys.columns c ON c.object_id = b.object_id AND b.column_id = c.column_id
30     WHERE a.object_id = OBJECT_ID(@TableName)
31       AND a.is_primary_key = 1),1,4,‘‘)
32
33
34
35 SELECT @Sql = ‘;WITH SOUR AS(
36 SELECT ‘+ CASE WHEN @XMLType = 1 THEN REPLACE(@Columns ,‘,‘,CHAR(10) + REPLICATE(CHAR(9),2) + ‘,‘)
37                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+ ‘)‘
38                          WHEN a.system_type_id IN (231,239) THEN ‘(‘ + CASE WHEN a.max_length = -1 THEN ‘max‘ ELSE RTRIM(a.max_length/2) END + ‘)‘
39                          WHEN a.system_type_id IN (59,106,108) THEN ‘(‘ + RTRIM(a.max_length) + ‘,‘ + RTRIM(a.scale) + ‘)‘
40                          ELSE ‘‘
41                          END + ‘‘‘) AS ‘ + a.name
42                         FROM sys.columns a
43                             WHERE object_id = OBJECT_ID(@TableName)
44                             ORDER BY column_id
45                             FOR XML PATH(‘‘)),1,2,‘‘)
46           ELSE ‘‘ END
47         + CASE WHEN @XMLType = 1 AND @HasAction = 1 THEN CHAR(10)+ REPLICATE(CHAR(9),2) + ‘,[Action]‘
48                WHEN @XMLType = 2 AND @HasAction = 1 THEN CHAR(10)+ REPLICATE(CHAR(9),2) + ‘,t.c.value(‘‘@Action‘‘,‘‘tinyint‘‘) [Action]‘
49           ELSE ‘‘ END
50     + ‘
51     FROM ‘ + CASE @XMLType WHEN 1 THEN ‘ OPENXML(@XmlInt,‘‘‘ + @Path + ‘‘‘,3)
52                     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 + ‘)‘
53                                                                   WHEN a.system_type_id IN (59,106,108) THEN ‘(‘ + RTRIM(a.precision) + ‘,‘ + RTRIM(a.scale)+ ‘)‘
54                                                              ELSE ‘‘ END + ‘ ‘‘‘ + a.name + ‘‘‘‘
55                                 FROM sys.columns a
56                                     INNER JOIN sys.systypes b ON a.system_type_id = b.xtype AND b.status = 0
57                                     WHERE object_id = OBJECT_ID(@TableName)
58                                       AND a.is_computed = 0
59                                       ORDER BY column_id
60                                       FOR XML PATH (‘‘)
61                                       ),1,8,‘‘) +
62                             + CASE WHEN @HasAction = 1 THEN CHAR(10)+ REPLICATE(CHAR(9),6) + ‘,[Action] tinyint ‘‘@Action‘‘)‘ ELSE ‘)‘ END
63                             WHEN 2 THEN ‘ @‘ + @TableName + ‘.nodes(‘‘‘+@Path+‘‘‘) as t(c)‘
64                             ELSE ‘‘ END
65              + ‘),
66 TAR AS( SELECT ‘ + REPLACE(@Columns,‘,‘,CHAR(10) + REPLICATE(CHAR(9),2) + ‘,‘) + ‘
67         FROM ‘ + @TableName + ‘)
68 MERGE TAR
69 USING SOUR
70 ON ‘+@On+‘
71 WHEN NOT MATCHED ‘ + CASE WHEN @HasAction = 1 THEN ‘ AND SOUR.[Action] = 1 ‘ ELSE ‘‘ END + ‘
72             THEN INSERT(‘ + @FilterColumns + ‘)‘ + CHAR(10) + REPLICATE(CHAR(9),5) + ‘ VALUES (SOUR.‘ + REPLACE(@FilterColumns,‘,‘,‘,SOUR.‘) + ‘)
73 WHEN MATCHED ‘ + CASE WHEN @HasAction = 1 THEN ‘ AND SOUR.[Action] = 2 ‘ ELSE ‘‘ END + ‘ THEN UPDATE SET ‘
74 + STUFF((    SELECT ‘,‘ + CHAR(10) + REPLICATE(CHAR(9),5) +  ‘TAR.[‘ + name + ‘]= SOUR.[‘ + name + ‘]‘
75         FROM sys.columns a
76             WHERE object_id = OBJECT_ID(@TableName)
77               AND is_computed = 0
78               AND is_identity = 0
79               AND NOT EXISTS(SELECT * FROM sys.foreign_key_columns WHERE parent_object_id = a.object_id AND parent_column_id = a.column_id)
80                 ORDER BY column_id
81             FOR XML PATH(‘‘)
82     ),1,6,‘‘) + ‘
83     ‘+ CASE WHEN @HasAction = 1 THEN ‘ WHEN MATCHED  AND SOUR.[Action] = 3 ‘ ELSE
84     ‘WHEN MATCHED BY SOURCE ‘ END + ‘ THEN Delete;‘
85 PRINT @Sql    

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

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

 1 ;WITH SOUR AS(
 2 SELECT t.c.value(‘(ID/text())[1]‘,‘int‘) AS ID
 3 ,t.c.value(‘(name/text())[1]‘,‘nvarchar(50)‘) AS name
 4 ,t.c.value(‘(age/text())[1]‘,‘int‘) AS age
 5 ,t.c.value(‘(birthdate/text())[1]‘,‘date‘) AS birthdate
 6 ,t.c.value(‘(salary/text())[1]‘,‘money‘) AS salary
 7         ,t.c.value(‘@Action‘,‘tinyint‘) [Action]
 8     FROM  @employee.nodes(‘root/employee‘) as t(c)),
 9 TAR AS( SELECT ID
10         ,name
11         ,age
12         ,birthdate
13         ,salary
14         FROM employee)
15 MERGE TAR
16 USING SOUR
17 ON TAR.ID = SOUR.ID
18 WHEN NOT MATCHED  AND SOUR.[Action] = 1
19             THEN INSERT(name,age,birthdate,salary)
20                      VALUES (SOUR.name,SOUR.age,SOUR.birthdate,SOUR.salary)
21 WHEN MATCHED  AND SOUR.[Action] = 2  THEN UPDATE SET     TAR.[name]= SOUR.[name],
22                     TAR.[age]= SOUR.[age],
23                     TAR.[birthdate]= SOUR.[birthdate],
24                     TAR.[salary]= SOUR.[salary]
25      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的匹配模型我是使用主键来进行对应

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

时间: 2024-10-25 08:56:39

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

为数据挖掘小组写的一个用于造数据的小程序

最近有个数据挖掘的项目,要求在文本里面写入随机字母并且要1000W个 于是就写了个程序用来造数据并记录一下 程序写的时候遇到的问题 1 未考虑内存溢出的情况,大批量的把数据写入导致内存溢出 以后需要谨慎对待 目前完整版 package test; import java.io.File; import java.io.FileWriter; import java.io.IOException; import org.apache.commons.io.FileUtils; import org

一个拆分haproxy serverlist的小脚本

公司对haproxy进行了配置的拆分,将每个backend的serverlist独立拆分成一个静态文件,对每个静态文件可以独立修改.. 现有的haproxy.cfg配置文件数量很多且每个文件的内容也非常的多, 人工拆分太苦逼, 因此写过一个小脚本用来完成这项任务. 今天在浏览系统文件夹的时候, 将此程序最初的一个版本贴上... #!/usr/bin/ruby # 2014/05/24 # coding by kevin hacfg=ARGV[0] if ARGV.empty?   puts 'P

写了一个预约东南大学体育场馆的python脚本,目前刚刚实现功能,后续会继续完善

看到git上有人写了一个自动预约的脚本,正好前段时间在学python爬虫和脚本,索性也写了一个,大佬直接略过. 目前没有做图形化,账号和预约信息也是手动输入的,我也只写了羽毛球和乒乓球,其实就是一个属性的值.嫌麻烦的同学可以写一个文本文件,保存这些信息,然后倒入到脚本里,每次稍作修改就可以了.如果基友固定的话,也可以写死在脚本里. 本篇博客只说下博主写脚本的时候遇到的问题和心路历程,只是想要代码的可以直接忽略下文,代码已经上传github:https://github.com/CooperXxx

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

package main import ( "bytes" "fmt" "os" "os/exec" "path/filepath" "sync" ) type jieguo struct { go_num int Lock sync.Mutex } var searchName string = os.Args[1] var search_result chan string = ma

shell实现一个简单的计算器功能小脚本

废话不多说,直接上代码,基本实现加减乘除功能: #!/bin/bash # author by alsww # date : 2016.02.03 # mail : [email protected] # blog : alsww.blog.51cto.com print_info(){     printf "请输入数字:\n" } print_err_num(){     printf "请输入正确的数字!\n" } print_err_fuhao(){    

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

基于http://www.cnblogs.com/HAOZHE/p/5276763.html改编写的关于随机生成四则运算的小程序 github源码和工程文件地址:https://github.com/HuChengLing/- 基本要求: 除了整数以外,还能支持真分数的四则运算. 对实现的功能进行描述,并且对实现结果要求截图. 主要功能:运算小学四则运算,可以选择加减乘除以及混合运算. 设计思想:首先思考运算数字范围,考虑小学生的运算能力,然后分类运算方法,分为加减乘除混合运算, 然后可以选择是

日志轮询的小脚本

在工作中各种服务会产生各种各样的日志文件,写了一个关于日志轮转的小工具,可以保存最近90天的日志,可以根据需要进行天数的修改,命令参数是日志所存在的路径和日知名如:/var/log/messag, 这个脚本会放在每天执行的计划任务中,可以将当天所存在的日志文件保存起来,以保证以后的查看.由于没有工作经验,能想到的只有这么多了希望各位大虾多多指点 #!/bin/bash LOG_PATH=`dirname $1` LOG_NAME=`basename $1` cd ${LOG_PATH} cp $

Ubuntu自动生成更换壁纸配置文件脚本的困惑

花了一整个下午研究了下Ubuntu怎么自动切换壁纸.其实,感觉还是很简单的,主要就是修改目录/usr/share/backgrouds/contest/trusty.xml的配置文件. 它的格式是这样的: 1 <background> 2 <starttime> 3 <year>2009</year> 4 <month>08</month> 5 <day>04</day> 6 <hour>00<

C# 写的一个生成随机汉语名字的小程序

最近因为要做数据库相关的测试,频繁使用到测试数据,手动添加太过于麻烦,而且复用性太差,因此干脆花了点时间写了一个生成随机姓名和相关数据的类,贴在这里,有需用的同志们可以参考一下.代码本身质量不好,也不算规范,各取所需莫要取笑-.- public class GetRandomName { private static string firstName = @"赵,钱,孙,李,周,吴,郑,王,冯,陈,褚,卫,蒋, 沈,韩,杨,朱,秦,尤,许,何,吕,施,张,孔,曹,严,华,金,魏,陶,姜, 戚,谢