这是我的问题的简化版本。
使用以下SELECT
语句,我将数据输出为Xml。
SET @result = (
SELECT * FROM MyTable
FOR XML path('receipts')
)
SELECT @result AS xmloutput
然后我将输出写入一个Xml文件,该文件使用文件名中的时间戳:
SET @sqlCommand =
'bcp "EXEC ' +@db + '.dbo.MyStoreProcedure" queryout "' + @filePath + @fileName + ' " -T -C 1252 -w'
EXEC master..xp_cmdshell @sqlCommand
在上面的代码段中:
MyStoreProcedure
基本上是第一个代码段中的代码,即SELECT
结果。@filename
的结构类似于YYYYMMDDHHMMSS_customers.xml
。现在问题是,应该读取此Xml文件的程序限制为20000条记录。我应该做的是将结果拆分为单独的Xml文件。因此,如果原始SELECT
查询提供25000条记录。它们应分成两个不重叠的文件:第一个包含20000,第二个包含剩余的5000。
为了避免覆盖同一个文件(如果进程非常快),我们可以在每个批处理之间等待1秒钟,以便下一个文件获得一个新名称。
如何实施此拆分?
提前致谢。
答案 0 :(得分:2)
function NTILE
(Starting with SQL Server 2012)允许您分组您的数据。如果您的版本较低,则可以使用ROW_NUMBER
和整数除法的组合轻松模拟此项。
以下内容将表行与块号一起写入临时表。 WHILE
在块之后占用大块。您可以使用chunk-number将其添加到文件名中。
function WAITFOR
(again 2012+)允许自动暂停。
DECLARE @ApproxRowsPerChunk INT=10; --will float a little...
SELECT NTILE((SELECT Count(*) FROM sys.objects) / @ApproxRowsPerChunk) OVER(ORDER BY o.object_id) AS ChunkNumber
,*
INTO #StagingTable
FROM sys.objects AS o;
DECLARE @nr INT=1;
DECLARE @maxNr INT=(SELECT MAX(ChunkNumber) FROM #StagingTable);
WHILE @nr<=@maxNr
BEGIN
SELECT * FROM #StagingTable WHERE ChunkNumber=@nr FOR XML PATH('test');
SET @nr=@nr+1;
WAITFOR DELAY '00:00:01';
END
这将允许您将 1 of 17 之类的内容集成到XML中(如果需要,还可以集成到文件名中)。
答案 1 :(得分:1)
请查看以下内容是否有帮助。我基本上把你完成的myTable
结果,分配row_number()
并将它们划分为分区,然后根据批量大小遍历分区,在循环中执行批量复制。您可能还需要做一些有关动态设置文件名的工作(您可以在文件名构建器中使用@current_partition
变量)。
我已经评论了我的代码:
-- Dummy data, represents your results set
IF OBJECT_ID('tempdb..#t1') IS NOT NULL
DROP TABLE #t1
CREATE TABLE #t1 (
initials VARCHAR(10)
,no_cars VARCHAR(10)
)
INSERT INTO #t1
VALUES
('AA',1)
,('BB',1)
,('CC',1)
,('DD',1)
,('EE',1)
,('FF',1)
,('GG',1)
,('HH',1)
,('II',1)
,('JJ',1)
,('KK',1)
---- end of test data creation
-- Assign query partition size, in your case would be 20,000. Must be float (or other decimal).
DECLARE @partition_size FLOAT = 3;
IF OBJECT_ID('tempdb..#t2') IS NOT NULL
DROP TABLE #t2;
-- Assign your results set a row number
WITH [cte1] AS (
SELECT
initials
,no_cars
,ROW_NUMBER() OVER (ORDER BY no_cars ASC) AS row_no
FROM #t1
)
-- Assign the query partition by running a ceiling command on the row number, store the results in a temp table
SELECT
initials
,no_cars
,CEILING(row_no/@partition_size) AS query_partition
INTO #t2
FROM cte1
--- Now, create a loop to go through each partition
-- Your business variables
DECLARE @result XML
DECLARE @sqlcommand NVARCHAR(4000)
DECLARE @db VARCHAR(50) = 'db'
DECLARE @filepath VARCHAR(50) = 'C:\temp'
DECLARE @filename VARCHAR(50) = 'dynamic2017010.xml'
-- Find highest partition
DECLARE @current_partition INT = 1
DECLARE @max_partition INT = (SELECT MAX(query_partition) FROM #t2)
WHILE @current_partition <= @max_partition
BEGIN
SET @result = (
SELECT initials
,no_cars FROM #t2
WHERE query_partition = @current_partition
FOR XML path('receipts')
)
SELECT @result AS xmloutput
-- other code..?
SET @sqlCommand =
'bcp "EXEC ' +@db + '.dbo.MyStoreProcedure" queryout "' + @filePath + @fileName + ' " -T -C 1252 -w'
EXEC master..xp_cmdshell @sqlCommand
SET @current_partition += 1
END