更新行时,如何还保留旧值并更新链接表?

时间:2018-08-28 07:26:01

标签: python sql sql-server tsql pyodbc

我有两个桌子。 ItemTableProductTableProductTable的{​​{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 = 0INSERT
  • 在同一行

此自动ItemIDLatest = 1最好仅使用纯SQL查询(也许使用INSERT,但我对此并不熟悉),或者可以通过以下方式实现一些Python代码。我将如何去做?

所需的最终结果:

UPDATE

3 个答案:

答案 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

上了解更多信息。

这是跟踪表更改的非常聪明的方法。它的性能很好,但是更改表结构需要一些工作。