我有一个SQL Server数据库,我需要手动执行更新查询。没有使用任何编程语言的解决方案。(可以使用存储过程)
我在查询中有4个表受影响(/已使用)。
我需要更新字段[Orders]。[OrderStatusID],它是[状态]的外键。 (所以实际上改变了订单的状态。表[StatusHistoryForOrder]是[StatusHistory]的链接表,只包含2个列。
不要说这在逻辑上不是因为我已经知道了。设计数据库的公司是一个完全迟钝的公司,但数据库现在太大而无法直接设置,没有时间或金钱去做。
[StatusHistory]表有多列:
[StatusHistory]。[OrderStatusId]也是[状态]的外键。
在更新查询中,我需要将订单状态更新为状态16.但仅限于现在状态为1且超过60天的行。我知道我可以使用函数
来检查日期DATEDIFF(DD,[StatusHistory].[Date],GETDATE()) > 60
但是如果日期字段不在订单中,如何实现此查询。要设置新的[StatusHistory],必须为该表创建一个新行,并且[StatusHistoryForOrder]表也需要一个新行,并且需要在[Orders]表行中设置该行的ID。
有谁知道怎么做?我对SQL Server(或SQL)相当新,我绝对不知道从哪里开始。
结论:
我需要一个存储过程,首先检查[Orders]中的每一行,如果[StatusHistory]。[Date](使用外键的订单链接)该订单的年龄大于60.如果它更旧那么必须插入一个新的StatusHistory行,其中包含当前日期和状态16.然后在[StatusHistoryForOrder]中必须插入一个新行,并在[StatusHistoryForOrder]中设置statusHistory的新ID。[OrderStatusHistoryid]并在[PageStatusHistoryid]中设置订单ID StatusHistoryForOrder] [单编号]。最后但并非最不重要的是:[Orders]。[OrderStatusID]也需要设置为16。
选择查询以选择订单的日期和状态:
SELECT TOP (100) PERCENT
dbo.Orders.OrderID,
dbo.Statuses.Description AS Status,
dbo.StatusHistory.Date
FROM
dbo.Orders
INNER JOIN
dbo.Statuses
ON
dbo.Orders.OrderStatusID = dbo.Statuses.StatusId
INNER JOIN
dbo.StatusHistoryForOrder
ON
dbo.Orders.OrderID = dbo.StatusHistoryForOrder.OrderId
INNER JOIN
dbo.StatusHistory
ON
dbo.StatusHistoryForOrder.OrderStatusHistoryid = dbo.StatusHistory.OrderStatusHistoryId
WHERE
(dbo.Statuses.StatusId = 1)
AND
(DATEDIFF(DD, dbo.StatusHistory.Date, GETDATE()) > 60)
更新 对于@marc_s:
任何人都可以帮助我吗?
答案 0 :(得分:1)
尝试使用此CTE(公用表表达式)查找所有这些订单 - 它是否有效,结果是否合理? (这还没有更新任何东西 - 现在只是选择):
USE (your database name here)
GO
DECLARE @OrdersToUpdate TABLE (OrderID INT, StatusHistoryID INT, StatusDate DATETIME)
;WITH RelevantOrders AS
(
SELECT
o.OrderId, sh.Date
FROM dbo.Orders o
INNER JOIN dbo.StatusHistoryForOrder ho ON ho.OrderId = o.OrderId
INNER JOIN dbo.StatusHistory sh ON ho.OrderStatusHistoryid = sh.OrderStatusHistoryid
WHERE
sh.Date <= DATEADD(D, -60, GETDATE()) -- older than 60 days back from today
AND o.OrderStatusID = 1 -- status = 1
)
INSERT INTO @OrdersToUpdate(OrderID, StatusDate)
SELECT OrderID, [Date]
FROM RelevantOrders
BEGIN TRANSACTION
BEGIN TRY
DECLARE @OrderIDToInsert INT, -- OrderID to process
@InsertedStatusHistoryID INT -- new ID of the inserted row in StatusHistory
-- grab the first OrderID that needs to be processed
SELECT TOP 1 @OrderIDToInsert = OrderID
FROM @OrdersToUpdate
WHERE StatusHistoryID IS NULL
ORDER BY OrderID
-- as long as there are still more OrderID to be processed ....
WHILE @OrderIDToInsert IS NOT NULL
BEGIN
PRINT 'Now inserting new StatusHistory entry for OrderID = ' + CAST(@OrderIDToInsert AS VARCHAR(10))
INSERT INTO dbo.StatusHistory(OrderStatusID, [Date], [Message])
VALUES(16, GETDATE(), 'Bulk Insert/Update operation') -- enter here whatever you want to store
SELECT @InsertedStatusHistoryID = SCOPE_IDENTITY(); -- grab newly inserted ID
PRINT 'New StatusHistory entry inserted with ID = ' + CAST(@InsertedStatusHistoryID AS VARCHAR(10))
UPDATE @OrdersToUpdate
SET StatusHistoryID = @InsertedStatusHistoryID
WHERE OrderID = @OrderIDToInsert
-- safety - reset @OrderIDToInsert to NULL so that we'll know when we're done
SET @OrderIDToInsert = NULL
-- read next OrderID to be processed
SELECT TOP 1 @OrderIDToInsert = OrderID
FROM @OrdersToUpdate
WHERE StatusHistoryID IS NULL
ORDER BY OrderID
END
-- insert into the StatusHistoryForOrder table
INSERT INTO dbo.StatusHistoryForOrder(OrderID, OrderStatusHistoryID)
SELECT OrderID, StatusHistoryID
FROM @OrdersToUpdate
-- update your Orders to status ID = 16
UPDATE dbo.Orders
SET OrderStatusID = 16
FROM @OrdersToUpdate upd
WHERE dbo.Orders.OrderID = upd.OrderID
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
ROLLBACK TRANSACTION
END CATCH
这个CTE基本上将你的Orders
表连接到StatusHistory
表(通过中间链接表)并选择你感兴趣的值(希望!)。
答案 1 :(得分:0)
这个特殊问题似乎只能通过设置操作来解决。
DECLARE @Orders TABLE (ID int, rownum int IDENTITY);
DECLARE @StatusHistory TABLE (ID int, rownum int IDENTITY);
/* get the list of orders with expired statuses */
INSERT INTO @Orders (ID)
SELECT o.OrderID
FROM Orders o
INNER JOIN StatusHistoryForOrder shfo ON o.OrderID = shfo.OrderId
INNER JOIN StatusHistory sh ON shfo.OrderStatusHistoryid = sh.OrderStatusHistoryId
GROUP BY o.OrderID
HAVING DATEDIFF(DD, MAX(sh.Date), GETDATE()) > 60
/* add so many new rows to StatusHistory and remember the new IDs */
INSERT INTO StatusHistory (OrderStatusId, Date, Message)
OUTPUT inserted.OrderStatusHistoryId INTO @StatusHistory (ID)
SELECT
16,
GETDATE(),
'Auto-inserted as the previous status has expired'
FROM @Orders
/* join the two temp lists together and add rows to StatusHistoryForOrder */
INSERT INTO StatusHistoryForOrder (OrderId, OrderStatusHistoryid)
SELECT o.ID, sh.ID
FROM @Orders o
INNER JOIN @StatusHistory sh ON o.rownum = sh.rownum
/* finally update the statuses in Orders */
UPDATE Orders
SET OrderStatusID = 16
FROM @Orders o
WHERE Orders.OrderID = o.ID
当然,这应该是单个交易的主体。