我有两个桌子。 ItemTable
和ProductTable
。 ProductTable
的{{1}}列链接到ItemID
的{{1}}列。两个表的ItemTable
列都是主键和标识列。
像这样:
ID
只要我想手动ID
ItemTable:
ID Col ColOther Latest Time
100 'old' 'oldother' 1 <Autogenerated timestamp>
ProductTable:
ID ItemID Value ValueOther Latest Time
12 100 'foo' 'bar' 1 <Autogenerated timestamp>
中的一行,通常只需一个查询即可完成>
UPDATE
我不想为ItemTable
做这些事情,而不是像上面那样做query = \
"""
UPDATE ItemTable
SET Col = ?, ColOther = ?
WHERE ID = 100;
"""
cursor.execute(query, 'new', 'newother')
:
UPDATE
使旧行具有ItemTable
UPDATE
包含更新后的值的行和Latest = 0
(假设此行的值是INSERT
250)然后Latest = 1
:
ID
在ProductTable中的旧链接行,以使ProductTable
UPDATE
与新的Latest = 0
和INSERT
此自动ItemID
和Latest = 1
最好仅使用纯SQL查询(也许使用INSERT
,但我对此并不熟悉),或者可以通过以下方式实现一些Python代码。我将如何去做?
所需的最终结果:
UPDATE
答案 0 :(得分:6)
为此使用OUTPUT:
我不会为此使用触发器,因为在触发器中进行大量活动会导致在发生其他更改时发生意外情况。相反,我正在使用存储过程
问题更改后,我重写了答案:
-- create test tables and test data
CREATE table item
(ID int identity,
Col varchar(99),
ColOther varchar(99),
Latest bit default 1,
Time datetime default getdate())
INSERT item(col, colother)
values('old','oldother')
CREATE table product
(ID int identity,
ItemID int,
[Value] varchar(20),
ValueOther varchar(20),
Latest bit default 1,
Time datetime default getdate())
INSERT product(itemid, [value], valueother)
values(1, 'foo', 'bar')
go
-- create procedure
CREATE procedure p_insert
(
@id int,
@col varchar(99),
@colOther varchar(99)
)
as
BEGIN tran t
DECLARE @out table(IDold int, IDnew int)
INSERT item(col, colother, Latest)
OUTPUT @id, inserted.id INTO @out
SELECT @col, @colother, 1
FROM item
WHERE
id = @id
and latest = 1
UPDATE i
SET Latest=0
FROM item i
JOIN @out o
ON o.IDold = i.id
and i.Latest=1
DECLARE @p table
(itemid int,
[value] varchar(20),
valueother varchar(20))
UPDATE p
SET Latest=0
OUTPUT o.IDnew, deleted.[value],deleted.[valueother]
INTO @p
FROM product p
JOIN @out o
ON p.ItemID = o.IDold
WHERE p.Latest=1
INSERT product(itemid, [value], valueother, Latest)
SELECT itemid, value, valueother, 1
FROM @p
commit tran t
要对此进行测试:
exec p_insert 1, 'a','b'
请注意,只有当您尝试更新存在Latest = 1的现有行时,此选项才起作用。
答案 1 :(得分:5)
下面的触发器将执行您想要的操作:
<form th:action="@{${action}}" th:object="${author}" method="POST">
<input type="hidden" th:field="*{id}">
<label class="font-weight-bold" for="firstName">
First Name
</label>
<input type="text" th:field="*{firstName}"
class="form-control mb-4 col-4" id="firstName" required>
<label class="font-weight-bold" for="lastName">
Last Name
</label>
<input type="text" th:field="*{lastName}"
class="form-control mb-4 col-4" id="Last Name" required>
<label class="font-weight-bold" for="middleName">
Middle Name or Initial
</label>
<input type="text" th:field="*{middleName}"
class="form-control mb-4 col-4" id="middleName">
<button type="submit" class="btn btn-info">Save</button>
</form>
创建触发器后,任何更新都会在CREATE TRIGGER ItemTable_OnUpdate
ON ItemTable
INSTEAD OF UPDATE
AS
BEGIN
DECLARE @newId int, @oldId int
INSERT INTO ItemTable(Col, ColOther, Latest)
SELECT Col, ColOther, 1 FROM INSERTED
--get old and new ids
SELECT @newId=@@IDENTITY, @oldId=ID FROM INSERTED
UPDATE ItemTable SET Latest=0 WHERE ID=@oldId
--updating ProductTable
INSERT INTO ProductTable (ItemID, [Value], ValueOther, Latest)
SELECT @newId, [Value], ValueOther, 1 FROM ProductTable WHERE ItemID=@oldId
UPDATE ProductTable SET Latest=0 WHERE ItemID=@oldId
END;
中插入新记录,并更新上一个记录。 ItemTable
,然后根据您的要求更新子表。
以下是我在以下更新后的输出:
Latest = 0
ItemTable:
UPDATE ItemTable SET col='new', ColOther='newother' WHERE ID=12;
ProductTable:
ID Col ColOther Latest Time
12 old oldother 0 0x00000000000007F0
13 new newother 1 0x00000000000007EF
对于多行更新,我们可以使用以下触发器,因为上面的触发器被设计为请求者指定的更新(一行)的参考。我相信下面将处理多行更新。请尝试。
ID ItemID Value ValueOther Latest Time
18 12 foo bar 0 0x00000000000007F2
19 13 foo bar 1 0x00000000000007F1
答案 2 :(得分:2)
如果您使用的是现代版本的SQL Server(即> = SQL Server 2016 SP1)
您是否考虑过为此使用临时表? 您可以在Microsofts BOL
上了解更多信息。这是跟踪表更改的非常聪明的方法。它的性能很好,但是更改表结构需要一些工作。