2011-03-16 29 views
3

我有一個SQL Server數據庫,我需要手動執行更新查詢。有沒有解決方案可以使用任何編程語言(可以使用存儲過程)SQL Server更新與WHERE跨越2個表

我有4個表影響(/使用)在查詢中。

  • [常規]
  • [StatusHistoryForOrder]
  • [StatusHistory] ​​
  • [以下狀態]

我需要更新的字段[常規]。[OrderStatusID]這是一個國外[狀態]鍵。 (因此,實際上改變順序的狀態。表[StatusHistoryForOrder]爲連接表[StatusHistory]和只包含2個colums。

  • [StatusHistoryForOrder] [單編號]
  • [StatusHistoryForOrder]。[ OrderStatusHistoryid]

不要說這在邏輯上不是因爲我已經知道了。誰設計的數據庫,該公司是一個完整的智障公司,但現在該數據庫太大,直設置的東西,既不存在的時間或金錢去做。

的〔StatusHistory]表具有多個列:

  • [StatusHistory] ​​[OrderStatusHistoryId]
  • [StatusHistory] ​​[OrderStatusId]
  • [StatusHistory] ​​[日期]
  • [StatusHistory]。 [Message]

[StatusHistory]。[OrderStatusId]也是[Statuses]的外鍵。

在更新查詢中,我需要將訂單的狀態更新爲狀態16.但是僅限於現在具有狀態1且比60天更早的行。我知道我可以使用函數檢查日期

DATEDIFF(DD,[StatusHistory].[Date],GETDATE()) > 60 

但是,如果日期字段不在訂單中,如何實現此查詢。爲了設置新的[StatusHistory],必須爲該表創建一個新行,並且[StatusHistoryForOrder]表還需要一個新行,並且需要在[Orders]錶行中設置該行的ID。

有誰知道如何做到這一點?我對SQL Server(或者SQL)相當陌生,而且絕對不知道從哪裏開始。

結論:

我需要一個存儲過程,首先檢查在[常規]中的每一行,如果[StatusHistory] ​​[日期](鏈接到使用外鍵的順序),該命令的是較舊的那60.如果它比較老,那麼必須插入一個新的StatusHistory行,其當前日期和狀態爲16.然後在[StatusHistoryForOrder]中必須插入一個新行,並在[StatusHistoryForOrder]中設置了statusHistory的新ID。[OrderStatusHistoryid]和[StatusHistoryForOrder]。[OrderId]中設置的訂單ID。最後但並非最不重要的是:[訂單]。[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) 

UPDATE 對於@marc_s:

Column info


任何人都可以幫助我嗎?

+0

@marc_s Microsoft SQL Server 2008 R2。使用WPI安裝。還使用:SQL Server Management Studio – SynerCoder 2011-03-16 09:08:22

+0

您是否有業務層? – 2011-03-16 09:40:39

+0

@Stefan Steinegger ,,我不知道你在說什麼。就像我說的,我對此很新。 – SynerCoder 2011-03-16 10:40:18

回答

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表(通過中間鏈路表),並選擇你感興趣的值(希望!)。

+0

@marc_s您的查詢沒有工作,不知道爲什麼。但前一陣子我可能會有類似的東西: – SynerCoder 2011-03-16 10:35:46

+0

@marc_s沒有錯誤。沒有行 – SynerCoder 2011-03-16 10:44:43

+0

@marc_s再次沒有行。我不知道爲什麼。即使我刪除查詢的整個where子句仍然沒有行。 ?!?!? – SynerCoder 2011-03-16 10:50:01

0

這個問題似乎只能用set操作解決。

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 

當然,這應該是單個交易的主體。

+0

您的解決方案給出了:(18679行受影響),而只有234行受到影響。 – SynerCoder 2011-03-17 07:33:17

+0

@SynerCoder:在哪一點? – 2011-03-17 07:38:36