个人博客 用于记载日常收集的一些技术文章 ...
云星空 : 修复内码:系统运维.数据库.修复种子表(单据) 云星空 : 修复内码:系统运维.数据库.修复种子表(单据) 原文链接:https://vip.kingdee.com/article/116231986418582016?productLineId=1&isKnowledge=2&lang=zh-CN


金蝶云星空中的数据表的主键通常情况下不会使用 自动递增ID,而是有一张与其表名相同仅前缀不同的种子表来负责产生 自动递增ID,

例如表 t_bas_voucher,其对应的种子表名为 z_bas_voucher。

当出现类似 以下的错误时,说明种子表可能已损坏(种子值被非法修改、重置等),需要手动修复。

insert into a_Gsf_BarPickEntry (FID,FEntryId) select 100033,100030

数据保存失败,错误提示:违反了 PRIMARY KEY 约束“pk_a_Gsf_BarPickEntry”。不能在对象“dbo.a_Gsf_BarPickEntry”中插入重复键。重复键值为 (100030)。
语句已终止。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
修复方法:

-- 1. 查看报错表的当前种子值,自动修复

dbcc checkIdent('Z_a_Gsf_BarPickEntry', noReSeed) -- 这一步就能修复,无需后面两步

-- 2. 查看报错表的主键最大值

declare @FID bigint
select @FID = isnull(max(FEntryId),100001) + 1 from a_Gsf_BarPickEntry
select @FID

-- 3. 更新种子值(更新前对比第一步和第二步获取的值,如果第一步获取的种子值更大,则无需更新)

dbcc checkIdent('Z_a_Gsf_BarPickEntry', reSeed, @FID)

种子表修复后,仍然需要去排查种子表损坏原因:

1. 是否有人为操作种子表?
2. 二开获取内码的方式是否正确?(只允许通过系统提供的 GetSequenceInt32,GetSequenceInt64,GetSequenceString 等方法获取)


星空提供的获取种子值的接口如下:

Kingdee.BOS.ServiceHelper.DBServiceHelper.GetSequenceInt32
Kingdee.BOS.ServiceHelper.DBServiceHelper.GetSequenceInt64
Kingdee.BOS.ServiceHelper.DBServiceHelper.GetSequenceString


【调用示例】

获取物料 (基础资料)主表种子值:Kingdee.BOS.ServiceHelper.DBServiceHelper.GetSequenceInt64(ctx,"T_BAS_ITEM",1)
获取物凭证(单据) 主表种子值:Kingdee.BOS.ServiceHelper.DBServiceHelper.GetSequenceInt64(ctx,"T_GL_VOUCHER",1)
郭少锋 编辑 2024-10-31 21:02:01 创建 2024-05-23 10:43:36 云星空
SQL : sql 闪回:数据恢复 SQL : sql 闪回:数据恢复 在Microsoft SQL Server中,“闪回”功能的概念与其他数据库系统中的实现略有不同。SQL Server提供了一些机制,可以实现类似闪回的效果,主要通过事务日志和时间旅行查询等功能。以下是关于SQL Server中实现闪回的几种方式:
1. 使用事务日志

SQL Server将所有的数据库更改记录在事务日志中。可以通过恢复模式和日志备份来实现数据的恢复。

完整恢复模式:在此模式下,SQL Server保留所有的事务日志,允许将数据库恢复到特定的时间点。
时间点恢复:可以使用RESTORE DATABASE命令与WITH STOPAT选项,恢复到某个具体的时间。

示例:

RESTORE DATABASE YourDatabase
FROM DISK = 'PathToYourBackup.bak'
WITH STOPAT = 'YYYY-MM-DD HH:MM:SS';

2. 使用临时表和快照

快照隔离:通过启用快照隔离,SQL Server允许用户查询某一时刻的数据状态,而不会被其他事务影响。
临时表:可以在进行重要的操作之前将数据复制到临时表中,以便在需要时恢复。

3. 使用系统版本化表

在SQL Server 2016及以后版本中,可以使用系统版本化表(System-Versioned Tables)来实现时间旅行功能。这种表自动保留历史记录,可以轻松查询过去的状态。

创建系统版本化表的示例:

CREATE TABLE Employees
(
EmployeeID INT PRIMARY KEY,
Name NVARCHAR(100),
ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START,
ValidTo DATETIME2 GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
) WITH (SYSTEM_VERSIONING = ON);

查询历史数据:

SELECT *
FROM Employees FOR SYSTEM_TIME AS OF 'YYYY-MM-DD HH:MM:SS';

4. 注意事项

性能:使用快照隔离和系统版本化表可能会影响性能,需要根据具体应用场景进行权衡。
存储:保持历史数据需要更多的存储空间,特别是在高频率更改的表上。

总结

虽然SQL Server没有直接称为“闪回”的功能,但通过事务日志、快照隔离和系统版本化表等机制,用户可以实现类似的效果。掌握这些功能,可以有效提高数据管理和恢复的灵活性。
郭少锋 创建 2024-10-30 20:55:45 SQL
K3 BOS : SQL 游标:逐行处理 K3 BOS : SQL 游标:逐行处理 -------------------------------------------------------------------------------------
-- 定义变量

DECLARE @UserId varchar(100),@username varchar(20)

-------------------------------------------------------------------------------------
-- 定义游标

DECLARE cursor1 CURSOR
FOR
SELECT TOP 10 UserId,UserName FROM UserInfo ORDER BY UserId DESC -- 数据来源

-------------------------------------------------------------------------------------
-- 打开游标 读取数据

OPEN cursor1 -- 打开游标
FETCH NEXT FROM cursor1 INTO @UserId,@username -- 抓取数据

-------------------------------------------------------------------------------------
-- 数据处理

WHILE @@FETCH_STATUS = 0
BEGIN
PRINT '用户ID:'+@UserId+' '+'用户名:'+@username

if @UserId = 0 begin

break; -- 跳出游标
end

FETCH NEXT FROM cursor1 INTO @UserId,@username
END

-------------------------------------------------------------------------------------
-- 关闭游标

CLOSE cursor1 -- 关闭游标
DEALLOCATE cursor1 -- 释放游标
郭少锋 编辑 2024-10-14 19:31:20 创建 2023-05-30 11:46:08 K3 BOS
windows : 使用命令行启用或禁用 Windows 11 休眠模式 windows : 使用命令行启用或禁用 Windows 11 休眠模式 powercfg -h on 启用休眠
powercfg -h off 禁用休眠

  1. 使用Windows + R快捷键打开「运行」,输入cmd,然后按下Ctrl + Shift + Enter以管理员权限启动「命令提示符」。

  2. 启用休眠模式(会自动创建休眠文件):powercfg /hibernate on

  3. 指定(标准)休眠模式文件类型和大小:powercfg /h /type full

  4. 现在,只需在「开始」菜单中点击电源菜单图标,你会发现休眠选项就在关机选项的上方。

  5. 执行以下命令来关闭并删除休眠文件:powercfg -h off
郭少锋 编辑 2024-10-04 20:24:16 创建 2023-11-13 18:57:06 windows
云星空 : 事务代码判断机制 云星空 : 事务代码判断机制 // 必须引用System.Transactions.dll

using (KDTransactionScope trans = new KDTransactionScope(System.Transactions.TransactionScopeOption.Required))
{
IOperationResult saveResult1 = saveService.Save(ctx, customer_info1, DynamicObjectList, null, "Save");
if (saveResult1 != null && saveResult1.IsSuccess == true)
{
IOperationResult saveResult2 = saveService.Save(ctx, customer_info2, DynamicObjectList, null, "Save");
}
trans.Complete();
}


如果saveResult1 成功,saveResult2失败,是否需要这样判断 ,saveResult1 成功saveResult2失败就无法处理
if (saveResult2 != null && saveResult2.IsSuccess == true) trans.Complete();

using (KDTransactionScope scope = new KDTransactionScope(TransactionScopeOption.Required))
{
DBUtils.ExecuteBatch(this.Context, lstSql);
scope.Complete();
}


//using Kingdee.BOS.App.Datausing (KDTransactionScope tran = new KDTransactionScope(TransactionScopeOption.Required)){//TODO:}


//外围事务
using (KDTransactionScope trans = new KDTransactionScope(TransactionScopeOption.Required))
{
...
try
{
//使用的是外围事务,如果发生异常,则外围事务也发生异常,即使使用try/catch吃掉异常,外围事务也处于异常状态(一般是abort状态)
//无需担心阻塞问题,可以对相同的表进行各种操作
using (KDTransactionScope trans1 = new KDTransactionScope(TransactionScopeOption.Required))
{
...
trans1.Complete();
}
//新建一个事务,外围事务发生异常不影响它,它发生异常,如果异常被吃掉不影响外围事务
//需要特别主要阻塞和死锁
using (KDTransactionScope trans1 = new KDTransactionScope(TransactionScopeOption.RequiresNew))
{
...
trans1.Complete();
}
//屏蔽事务
using (KDTransactionScope trans1 = new KDTransactionScope(TransactionScopeOption.Suppress))
{
...
// trans1.Complete();
}
}
catch (Exception ex)
{
}
trans.Complete();
}

郭少锋 创建 2024-09-16 09:48:57 云星空
SQL : sql 嵌套事务 SQL : sql 嵌套事务

drop table dbo.test
go
create table dbo.test ( ID int, UserID int, Name varchar(100) )
go


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 父过程如下:


drop procedure aTran_1
go
create procedure aTran_1

@ID BIGINT,
@UserID BIGINT,
@Name varchar(50)
as
declare @tranCount int ; set @tranCount = ( select @@tranCount ) ; print '执行【begin tran】 进入 父事务前 全局 @@tranCount = ' + cast( @tranCount as varchar(50) ) -- 执行【begin tran】 进入 父事务前 全局 @@tranCount = 0

begin tran ; set @tranCount = ( select @@tranCount ) ; print '执行【begin tran】 进入 父事务后 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) -- 执行【begin tran】 进入 父事务后 全局 @@tranCount = 1

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 调用 第2层事务

declare @result int ; exec @result = aTran_2 @ID = @ID, @UserID = @UserID, @Name = @Name ; print '执行【exec @result = aTran_2 ... 】 执行 子事务后 @result = '+ cast( @result as varchar(50) ) ; -- 执行【exec @result = aTran_2 ... 】 执行 子事务后 @result = 3

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IF ( @result != 3 )
begin

set @tranCount = ( select @@tranCount ) ; print '执行【rollBack tran】 回滚 父事务前 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) -- 进入 父事务后 全局 @@tranCount = 1

rollBack tran ; set @tranCount = ( select @@tranCount ) ; print '执行【rollBack tran】 回滚 父事务后 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) --

return ;
end

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
commit tran ; set @tranCount = ( select @@tranCount ) ; print '执行【commit tran】 提交 父事务后 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) -- 提交 父事务后 全局 @@tranCount = 0
go


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 子存储过程如下:


--内层事务存储过程,演示如何处理才能在嵌套的事务存储过程中正确处理事务

drop procedure aTran_2
go
create procedure aTran_2

@ID BIGINT ,
@UserID BIGINT ,
@Name varchar(50)
as
begin

declare @tranCount int ; set @tranCount = ( select @@tranCount ) ; print '执行【set xact_abort on】前 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) -- 执行【set xact_abort on】前 全局 @@tranCount = 1

set xact_abort on ; set @tranCount = ( select @@tranCount ) ; print '执行【set xact_abort on】后 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) -- 执行【set xact_abort on】后 全局 @@tranCount = 1

------------------------------------------------------------------------------------------------------------------------------------------------------
begin tran tran02 ; set @tranCount = ( select @@tranCount ) ; print '执行【begin tran tran02】进入 子事务后 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) -- 执行【begin tran tran02】进入 子事务后 全局 @@tranCount = 2

------------------------------------------------------------------------------------------------------------------------------------------------------
save tran tran_01 ; set @tranCount = ( select @@tranCount ) ; print '执行【save tran tran_01】 保存 事务点后 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) -- 执行【save tran tran_01】 保存 事务点后 全局 @@tranCount = 2


------------------------------------------------------------------------------------------------------------------------------------------------------
-- 条件判断,回滚事务

IF EXISTS( SELECT TOP 1 * FROM dbo.test WHERE ID = @ID )
begin

rollBack tran tran_01 ; set @tranCount = ( select @@tranCount ) ; print '执行【rollBack tran tran_01】回滚 保存点 事务后 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) --

commit tran tran02x ; set @tranCount = ( select @@tranCount ) ; print '执行【commit tran tran02】提交 子事务后 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) --

return 1 ; -- 1 已存在 ID
end

------------------------------------------------------------------------------------------------------------------------------------------------------
-- 业务逻辑 开始

insert test ( ID, UserID, Name) VALUES ( @ID ,@UserID ,@Name) -- (1 行受影响)

-- 业务逻辑 结束

begin tran tran03 ; save tran tran03 ;

insert test ( ID, UserID, Name) VALUES ( @ID+100 ,@UserID ,@Name) -- (1 行受影响)

commit tran tran02x ;
rollBack tran tran03 ;
------------------------------------------------------------------------------------------------------------------------------------------------------
-- 执行过程中,发生错误

IF @@error <> 0
begin

rollBack tran tran_01 ; set @tranCount = ( select @@tranCount ) ; print '执行【rollBack tran tran_01】回滚 保存点 事务后 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) --

commit tran tran02x ; set @tranCount = ( select @@tranCount ) ; print '执行【commit tran tran02】提交 子事务后 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) --

return 2 ; -- '执行过程中,发生错误 !'
end

------------------------------------------------------------------------------------------------------------------------------------------------------
commit tran tran02x ; set @tranCount = ( select @@tranCount ) ; print '执行【commit tran tran02】 提交 子事务后 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) -- 执行【commit tran tran02】 提交 子事务后 全局 @@tranCount = 1

set xact_abort off; set @tranCount = ( select @@tranCount ) ; print '执行【set xact_abort off】后 全局 @@tranCount = '+ cast( @tranCount as varchar(50) ) -- 执行【set xact_abort off】后 全局 @@tranCount = 1

return 3 ; -- '执行完毕 !'

end
go



---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 调用父存储过程:


select * from test

declare @return_value int

exec @return_value = aTran_1 @ID = 1 ,@UserID = 0 ,@Name = '0'

print 'return Value = '+ cast( @return_value as varchar(50) )

select * from test

/*
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 结果如下:

(0 行受影响)
执行【begin tran】 进入 父事务前 全局 @@tranCount = 0
执行【begin tran】 进入 父事务后 全局 @@tranCount = 1
执行【set xact_abort on】前 全局 @@tranCount = 1
执行【set xact_abort on】后 全局 @@tranCount = 1
执行【begin tran tran02】进入 子事务后 全局 @@tranCount = 2
执行【save tran tran_01】 保存 事务点后 全局 @@tranCount = 2

(1 行受影响)
执行【commit tran tran02】 提交 子事务后 全局 @@tranCount = 1
执行【set xact_abort off】后 全局 @@tranCount = 1
消息 245,级别 16,状态 1,过程 aTran_2,行 58 [批起始行 114]
在将 varchar 值 '执行完毕 !' 转换成数据类型 int 时失败。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
不会再报"execute 后的事务计数指示 begin 和 commit 语句的数目不匹配"之类的错误了,

实际上就是在每个嵌套的子过程中标明当前事务点,
每个子事务 只提交/回滚 子事务点,
而不是回滚整个事务!

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SET xact_abort { ON | OFF }

注释
当 SET xact_abort 为 ON 时,如果 Transact-SQL 语句产生运行时错误,整个事务将终止并回滚。为 OFF 时,只回滚产生错误的 Transact-SQL 语句,而事务将继续进行处理。编译错误(如语法错误)不受 SET xact_abort 的影响。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*/

郭少锋 编辑 2024-09-14 08:54:26 创建 2024-09-13 23:08:31 SQL
Access : 读取选中的行 Access : 读取选中的行 Dim aSelTop As Long, aSelCount As Long

Private Sub 子窗体_Exit(Cancel As Integer)

aSelTop = Me.子窗体.Form.SelTop '从第n行 开始选中
aSelCount = Me.子窗体.Form.SelHeight '共选中x行

End Sub

Private Sub 追加_Click()

Dim i As Long, aControls As Controls, aControl As Control

Set aControls = Me.临时表子窗体.Form.Controls

Me.临时表子窗体.SetFocus


For i = 0 To aSelCount - 1 '逐行读取

Me.子窗体.Form.SelTop = aSelTop + i

If Me.临时表子窗体.Form.NewRecord <> True Then

DoCmd.RunCommand acCmdRecordsGoToNew '定位到 新增行
End If

For Each aControl In aControls

If aControl.ControlType <> acLabel Then

aControl.Value = Me.子窗体.Form.Controls(aControl.Name).Value '逐个字段赋值
End If

Next aControl

Me.临时表子窗体.Form.Recalc
Next

End Sub
郭少锋 创建 2024-09-02 23:31:15 Access
Access : 窗体 过滤数据 Access : 窗体 过滤数据 Private Sub Form_Load()

Call Allfilter
End Sub


Sub Allfilter()

Dim strWh As String

strWh = "True"

If IsNull(Me.姓氏.Value) = False Then
strWh = strWh & " and 姓名 like '" & Me.姓氏.Value & "*'"
End If

If IsNull(Me.性别.Value) = False Then
strWh = strWh & " and 性别= '" & Me.性别.Value & "'"
End If

Me.子窗体.Form.Filter = strWh
Me.子窗体.Form.FilterOn = True

End Sub
郭少锋 创建 2024-09-02 23:14:56 Access
Access : 打开关闭 Access : 打开关闭 Private Sub Cmd_Frm_Click()

DoCmd.OpenForm "frmopen", acDesign '打开 窗体设计器
End Sub

Private Sub Cmd_mod_Click()

DoCmd.OpenModule "Form_frmOpen" '打开 代码设计器
End Sub

Private Sub CmdClose_Click()

DoCmd.Close '关闭窗口
End Sub

Private Sub CmdQuit_Click()

DoCmd.Quit '退出 Access
End Sub
郭少锋 创建 2024-09-02 23:06:05 Access
Access : 定位到 之前选中记录 Access : 定位到 之前选中记录 子窗体Requery后重新定位之前选中记录

1、子窗体刷新之前,先记录一下当前记录的位置
Dim lngPostion As Long
lngPostion = Me.FrmSub.Form.CurrentRecord '获取子窗体FrmSub当前记录的位置

2、子窗体刷新之后,重新定位当前记录的位置
Me.FrmSub.SetFocus '先让子窗体获得焦点
Docmd.GotoRecord , , acGoTo, lngPostion '根据前面记录的位置跳转到对应的位置

这样两步走,就可以实现子窗体Requery刷新数据之后,重新定位记录游标的位置
郭少锋 创建 2024-09-02 23:02:11 Access