将表里的数据批量生成INSERT语句的存储过程 增强版
有时候,我们需要将某个表里的数据全部或者根据查询条件导出来,迁移到另一个相同结构的库中
目前SQL Server里面是没有相关的工具根据查询条件来生成INSERT语句的,只有借助第三方工具(third party tools)
这种脚本网上也有很多,但是网上的脚本还是欠缺一些规范和功能,例如:我只想导出特定查询条件的数据,网上的脚本都是导出全表数据
如果表很大,对性能会有很大影响
这里有一个存储过程( 适用于SQLServer2005 或以上版本 )
--
Author: <桦仔>
--
Blog: <http://www.cnblogs.com/lyhabc/>
--
Create date: <2014/10/18>
--
Description: <根据查询条件导出表数据的insert脚本>
--
=============================================
CREATE
PROCEDURE
InsertGenerator
(
@tableName
NVARCHAR
(
MAX
),
@whereClause
NVARCHAR
(
MAX
)
)
AS
--
Then it includes a cursor to fetch column specific information (column name and the data type thereof)
--
from information_schema.columns pseudo entity and loop through for building the INSERT and VALUES clauses
--
of an INSERT DML statement.
DECLARE
@string
NVARCHAR
(
MAX
)
--
for storing the first half of INSERT statement
DECLARE
@stringData
NVARCHAR
(
MAX
)
--
for storing the data (VALUES) related statement
DECLARE
@dataType
NVARCHAR
(
MAX
)
--
data types returned for respective columns
DECLARE
@schemaName
NVARCHAR
(
MAX
)
--
schema name returned from sys.schemas
DECLARE
@schemaNameCount
int
--
shema count
DECLARE
@QueryString
NVARCHAR
(
MAX
)
--
provide for the whole query,
set
@QueryString
=
'
'
--
如果有多个schema,选择其中一个schema
SELECT
@schemaNameCount
=
COUNT
(
*
)
FROM
sys.tables t
INNER
JOIN
sys.schemas s
ON
t.schema_id
=
s.schema_id
WHERE
t.name
=
@tableName
WHILE
(
@schemaNameCount
>
0
)
BEGIN
--
如果有多个schema,依次指定
select
@schemaName
=
name
from
(
SELECT
ROW_NUMBER()
over
(
order
by
s.schema_id) RowID,s.name
FROM
sys.tables t
INNER
JOIN
sys.schemas s
ON
t.schema_id
=
s.schema_id
WHERE
t.name
=
@tableName
)
as
v
where
RowID
=
@schemaNameCount
--
Declare a cursor to retrieve column specific information
--
for the specified table
DECLARE
cursCol
CURSOR
FAST_FORWARD
FOR
SELECT
column_name ,
data_type
FROM
information_schema.columns
WHERE
table_name
=
@tableName
AND
table_schema
=
@schemaName
OPEN
cursCol
SET
@string
=
'
INSERT INTO [
'
+
@schemaName
+
'
].[
'
+
@tableName
+
'
](
'
SET
@stringData
=
''
DECLARE
@colName
NVARCHAR
(
500
)
FETCH
NEXT
FROM
cursCol
INTO
@colName
,
@dataType
PRINT
@schemaName
PRINT
@colName
IF
@@fetch_status
<>
0
BEGIN
PRINT
'
Table
'
+
@tableName
+
'
not found, processing skipped.
'
CLOSE
curscol
DEALLOCATE
curscol
RETURN
END
WHILE
@@FETCH_STATUS
=
0
BEGIN
IF
@dataType
IN
(
'
varchar
'
,
'
char
'
,
'
nchar
'
,
'
nvarchar
'
)
BEGIN
SET
@stringData
=
@stringData
+
'''''''''
+
isnull(
'
+
@colName
+
'
,
''''
)+
''''''
,
''
+
'
END
ELSE
IF
@dataType
IN
(
'
text
'
,
'
ntext
'
)
--
if the datatype
--
is text or something else
BEGIN
SET
@stringData
=
@stringData
+
'''''''''
+
isnull(cast(
'
+
@colName
+
'
as nvarchar(max)),
''''
)+
''''''
,
''
+
'
END
ELSE
IF
@dataType
=
'
money
'
--
because money doesn't get converted
--
from varchar implicitly
BEGIN
SET
@stringData
=
@stringData
+
'''
convert(money,
''''''
+
isnull(cast(
'
+
@colName
+
'
as nvarchar(max)),
''
0.0000
''
)+
''''''
),
''
+
'
END
ELSE
IF
@dataType
=
'
datetime
'
BEGIN
SET
@stringData
=
@stringData
+
'''
convert(datetime,
''''''
+
isnull(cast(
'
+
@colName
+
'
as nvarchar(max)),
''
0
''
)+
''''''
),
''
+
'
END
ELSE
IF
@dataType
=
'
image
'
BEGIN
SET
@stringData
=
@stringData
+
'''''''''
+
isnull(cast(convert(varbinary,
'
+
@colName
+
'
)
as varchar(6)),
''
0
''
)+
''''''
,
''
+
'
END
ELSE
--
presuming the data type is int,bit,numeric,decimal
BEGIN
SET
@stringData
=
@stringData
+
'''''''''
+
isnull(cast(
'
+
@colName
+
'
as nvarchar(max)),
''
0
''
)+
''''''
,
''
+
'
END
SET
@string
=
@string
+
'
[
'
+
@colName
+
'
]
'
+
'
,
'
FETCH
NEXT
FROM
cursCol
INTO
@colName
,
@dataType
END
--
After both of the clauses are built, the VALUES clause contains a trailing comma which needs to be replaced with a single quote. The prefixed clause will only face removal of the trailing comma.
DECLARE
@Query
NVARCHAR
(
MAX
)
--
provide for the whole query,
--
you may increase the size
PRINT
@whereClause
IF
(
@whereClause
IS
NOT
NULL
AND
@whereClause
<>
''
)
BEGIN
SET
@query
=
'
SELECT
'''
+
SUBSTRING
(
@string
,
0
,
LEN
(
@string
))
+
'
) VALUES(
''
+
'
+
SUBSTRING
(
@stringData
,
0
,
LEN
(
@stringData
)
-
2
)
+
'''
+
''
)
''
FROM
'
+
@schemaName
+
'
.
'
+
@tableName
+
'
WHERE
'
+
@whereClause
PRINT
@query
--
EXEC sp_executesql @query --load and run the built query
--
Eventually, close and de-allocate the cursor created for columns information.
END
ELSE
BEGIN
SET
@query
=
'
SELECT
'''
+
SUBSTRING
(
@string
,
0
,
LEN
(
@string
))
+
'
) VALUES(
''
+
'
+
SUBSTRING
(
@stringData
,
0
,
LEN
(
@stringData
)
-
2
)
+
'''
+
''
)
''
FROM
'
+
@schemaName
+
'
.
'
+
@tableName
END
CLOSE
cursCol
DEALLOCATE
cursCol
SET
@schemaNameCount
=
@schemaNameCount
-
1
IF
(
@schemaNameCount
=
0
)
BEGIN
SET
@QueryString
=
@QueryString
+
@query
END
ELSE
BEGIN
SET
@QueryString
=
@QueryString
+
@query
+
'
UNION ALL
'
END
PRINT
convert
(
varchar
(
max
),
@schemaNameCount
)
+
'
---
'
+
@QueryString
END
EXEC
sp_executesql
@QueryString
--
load and run the built query
--
Eventually, close and de-allocate the cursor created for columns information.
这里要声明一下,如果你有多个schema,并且每个schema下面都有同一张表,那么脚本只会生成其中一个schema下面的表insert脚本
比如我现在有三个schema,下面都有customer这个表
CREATE
TABLE
dbo.
[
customer
]
(city
int
,region
int
)
CREATE
SCHEMA
test
CREATE
TABLE
test.
[
customer
]
(city
int
,region
int
)
CREATE
SCHEMA
test1
CREATE
TABLE
test1.
[
customer
]
(city
int
,region
int
)
在执行脚本的时候他只会生成dbo这个schema下面的表insert脚本
INSERT
INTO
[
dbo
]
.
[
customer
]
(
[
city
]
,
[
region
]
)
VALUES
(
'
1
'
,
'
2
'
)
这个脚本有一个缺陷
无论你的表的字段是什麽数据类型,导出来的时候只能是字符
表结构
CREATE
TABLE
[
dbo
]
.
[
customer
]
(city
int
,region
int
)
导出来的insert脚本
INSERT
INTO
[
dbo
]
.
[
customer
]
(
[
city
]
,
[
region
]
)
VALUES
(
'
1
'
,
'
2
'
)
我这里演示一下怎麽用
有两种方式
1、导全表数据
InsertGenerator
'
customer
'
,
null
或
InsertGenerator
'
customer
'
,
'
'
2、根据查询条件导数据
InsertGenerator
'
customer
'
,
'
city=3
'
或者
InsertGenerator
'
customer
'
,
'
city=3 and region=8
'
点击一下,选择全部
然后复制
新建一个查询窗口,然后粘贴
其实SQLServer的技巧有很多
最后,大家可以看一下代码,非常简单,如果要支持SQLServer2000,只要改一下代码就可以了
补充:创建一张测试表
CREATE
TABLE
testinsert (id
INT
,name
VARCHAR
(
100
),cash
MONEY
,dtime
DATETIME
)
INSERT
INTO
[
dbo
]
.
[
testinsert
]
(
[
id
]
,
[
name
]
,
[
cash
]
,
[
dtime
]
)
VALUES
(
1
,
--
id - int
'
nihao
'
,
--
name - varchar(100)
8.8
,
--
cash - money
GETDATE
()
--
dtime - datetime
)
SELECT
*
FROM
[
dbo
]
.
[
testinsert
]
测试
InsertGenerator
'
testinsert
'
,
''
InsertGenerator
'
testinsert
'
,
'
name=
''
nihao
'''
InsertGenerator
'
testinsert
'
,
'
name=
''
nihao
''
and cash=8.8
'
datetime类型会有一些问题
生成的结果会自动帮你转换
INSERT
INTO
[
dbo
]
.
[
testinsert
]
(
[
id
]
,
[
name
]
,
[
cash
]
,
[
dtime
]
)
VALUES
(
'
1
'
,
'
nihao
'
,
convert
(
money
,
'
8.80
'
),
convert
(
datetime
,
'
02 8 2015 5:17PM
'
))
如有不对的地方,欢迎大家拍砖o(∩_∩)o

