【问题标题】:How to select and export 5,000 lines of debit and credit transactions at a time and have the debits and credits balance to zero?如何一次选择并导出 5,000 行借记和贷记交易,并使借记和贷记余额为零?
【发布时间】:2019-07-12 10:19:05
【问题描述】:

我们要迁移到的 ERP 系统需要包含 5,000 行或更少行的 csv 文件用于 GL。每个文件中的借记和贷记交易必须平衡为零。有多个借记和贷记交易行共享一个公共交易 ID。

使用 offset 和 fetch next 我已经能够一次提取 5000 行,但是贷方和借方不平衡。

数据示例:

TranID  Credit  Debit   Balance Account#
1       250     0       250     ABC
1       0       250     0       DEF
2       0       100     -100    GHI
2       50      0       -50     JKL
2       50      0       0       MNO


declare @batchsize INT = 5000,
    @loopcount INT = 0;

while (@loopcount*@batchsize < (select  count(*) from [Apps2].[dbo].[GLTrans]))
begin
  SELECT *  FROM [Apps2].[dbo].[GLTrans]
  ORDER BY tranID
  offset (@batchsize * @loopcount) rows
  fetch next (@batchsize) rows only

  set @loopcount= @loopcount + 1
end

【问题讨论】:

  • 所以每笔交易的总和为零?那么问题是如何在不拆分事务的情况下找到尽可能多的行,最多 5000 行?
  • 是的,卢比。你是对的,尽可能多的行最多 5000 行而不拆分事务(tranid)。
  • 将运行总计连同行号和 id 计算到临时表中,然后找到运行总计为零的小于 5000 的最高行号?
  • 选择 5000 行,然后丢弃那些具有“最后一个”事务 ID 的行。

标签: sql sql-server tsql sql-server-2012


【解决方案1】:

一个简单的解决方案是预处理所有交易并分配一个批次编号(针对每个 CSV 文件)。临时表存储了每个 TranID 的行数。

假设每个 TranID 的借方和贷方将保持平衡。

之后,您可以根据临时表生成 CSV。

-- create the temp table
create table #trans
(
    TranID      int identity,
    Cnt         int,
    Batch       int
)

-- populate the temp table
insert into #trans (TranID, Cnt)
select TranID, Cnt = count(*)
from   [Apps2].[dbo].[GLTrans]
group by TranID

declare @batchsize  int = 5000,
        @batch      int = 1

while   exists (select * from #trans where Batch is null)
begin
    update  t
    set     Batch   = @batch 
    from
    (
        select  *, cumm = sum(Cnt) over (order by TranID)
        from    #trans
        where   Batch   is null
    ) t
    where   cumm    <= @batchsize 

    select  @batch = @batch + 1
end

--  Verify
select  *, sum(Cnt) over (partition by Batch order by TranID)
from    #trans 
order by TranID 

【讨论】:

  • 松鼠,这适用于我的初始通行证。我的用户希望在我们创建的 5000 个批次中拥有一个子批次,将交易分成 500 个或更少的组。我已经尝试在它自己的内部重用上面的代码来做到这一点,但一直遇到错误。关于如何实现这一点的任何见解?
  • 不太了解您对子批次的要求。也许您可以提出一个新问题并发布您的查询
【解决方案2】:

使用表变量来遍历您的数据。有点像在 Oracle 中使用游标...

如果我正确理解了您的示例数据并且我假设每个 transID 设置为 0,您可以将循环逻辑更改为更像一个 do...while like this example here 您获取下一个事务集并决定如果它使批次保持在 5k 以下。 这应该包括填充一批 5000 行或更少的行,假设每个事务 ID 设置净值为 0 美元

Declare @batchCursor TABLE (
    TransID INT,
    Credit INT, -- chose int for expediency 
    Debit INT,
    Balance INT,
    AccountNo Varchar(4)

),

@batchsize INT = 5000,
@rowCount INT = 0,
@transID INT = 1,
@transSize INT = 0;

while (@rowcount <= 5000)
BEGIN
    INSERT INTO @batchCursor
    SELECT * FROM [Apps2].[dbo].[GLTrans] -- you might need to enumerate all your column names
    WHERE TransID = @transID;

    SELECT @transSize = COUNT(*) FROM @batchCursor where TransID = @transID);

    IF(@transSize > 0)
        BEGIN
        IF (@transSize + @rowCount < @batchSize)
           BEGIN
           Set @rowCount += transSize;
           Set @transID += 1;
           END;
        END;
    ELSE Set @transID += 1;

IF((Select count(*) FROM [Apps2].[dbo].[GLTrans] WHERE TransID = @transID) + @rowCount > @batch)
BREAK;

END;

【讨论】:

    猜你喜欢
    • 2017-07-29
    • 1970-01-01
    • 2011-08-10
    • 2021-04-02
    • 2016-06-16
    • 2017-01-27
    • 2021-11-18
    • 1970-01-01
    • 2020-11-18
    相关资源
    最近更新 更多