0

嗨,我在处理一个特定的 SQL 查询时遇到问题,问题如下:我有两个表,其中一个包含当前在一个产品中的项目,第二个是更改历史记录。每次编辑一个项目时,他的先前状态都会保存在历史表中,并且更改的时间和日期写入项目表的 item_edited 列中。如果项目被删除,它将从项目表中删除,并在历史表中插入具有项目最后状态的新行,并且删除日期写入历史表中的 item_deleted 列。如果未编辑项目 item_edited 的值为 NULL,并且如果未删除项目 item_deleted 的值为 NULL。

我需要编写 SQL 查询来返回特定日期的产品状态(该日期的项目和编号)

项目

product_Id (uniqueidentifier,null)  
item_Id (PK,bigint,not null)
item_name (varchar(200),not null)
item_number_of_items (int,null)
item_created (datetime,null)
item_created_by_person (uniqueidentifier,null)  
item_edited (datetime,null)
item_edited_by_person (uniqueidentifier,null)  

历史

history_Id (PK,bigint,not null)
product_Id (uniqueidentifier,null)  
item_Id (PK,bigint,not null)
item_name (varchar(200),not null)
item_number_of_items (int,null)
item_created (datetime,null)
item_created_by_person (uniqueidentifier,null)  
item_edited (datetime,null)
item_edited_by_person (uniqueidentifier,null)
item_deleted (datetime,null)

这就是我现在所拥有的,问题是我从历史记录中获得了重复的项目,例如,如果一个特定项目的历史记录中有更多“编辑”状态,则此查询返回所选日期之前的所有状态,所以我得到重复的项目在最终结果中。而且我需要一些条件来从历史中选择仅在选定日期之前最新编辑且未在选定日期之前删除且不在项目表中的项目。

    DECLARE @selectDate DATETIME 
    SET @selectDate = '2013/05/9' 
    DECLARE @Product_Id UNIQUEIDENTIFIER
    SET @Product_Id = 'AF4A8D96-2B9B-4C09-8FA3-C6BE20CFD391'

    SELECT item_Id,
           item_name,
           item_number_of_items,
           item_created,
           item_created_by_person,
           item_edited,
           item_edited_by_person
    FROM Items WHERE    product_Id=@Product_Id 
    AND FLOOR(CAST (ISNULL(item_edited,item_created) AS FLOAT)) <= FLOOR(CAST(@selectDate AS FLOAT))

    UNION ALL 

    SELECT item_Id,
           item_name,
           item_number_of_items,
           item_created,
           item_created_by_person,
           item_edited,
           item_edited_by_person
   FROM History 

   WHERE product_Id=@Product_Id 

   AND FLOOR(CAST (ISNULL(item_edited,item_created) AS FLOAT)) <= FLOOR(CAST(@selectDate AS FLOAT))
   AND (FLOOR(CAST(item_deleted AS FLOAT)) > FLOOR(CAST(@selectDate AS FLOAT)) OR item_deleted IS NULL)
   AND item_Id NOT IN (SELECT item_Id FROM item WHERE product_Id=@Product_Id 
                      AND FLOOR(CAST (ISNULL(item_edited,item_created) AS FLOAT)) <= FLOOR(CAST(@selectDate AS FLOAT)))
4

2 回答 2

0

首先,听起来您只是item_edited在编辑时更新,而不是插入或删除。最好将其重命名为LastModified或类似的名称,并针对状态的每次更改进行更新,无论是原始插入、编辑还是删除。
然后你就可以写了。

 Select * From History h
 Where item_edited = 
     (Select Max(item_edited)
      From History
      Where item_Id = h.item_Id
          And item_edited < @AsOfDatetime)

如果不是,那么我希望您在最初插入新行时向历史表中插入一条记录,并且每次编辑记录时都插入一条具有新当前状态的新记录,而不是插入一个进行编辑时具有旧状态的历史记录行。在前一种情况下,当前状态重复并且始终是历史表和当前表中的最新行。

如果是这样,那么你可以写

 Select * From History h
 Where Coalesce(item_deleted, item_edited, item_created) = 
     (Select Max(Coalesce(item_deleted, item_edited, item_created))
      From History
      Where item_Id = h.item_Id
          And item_edited < @AsOfDatetime)
于 2013-05-28T15:45:49.643 回答
0

好的,谢谢您的帮助,它实际上将我引导到了正确的方向:) 好的,这是我的解决方案:

CREATE TABLE #ITEMS_CURENTSTATE (item_Id BIGINT,
        item_name VARCHAR(100),
        item_number_of_items INT,
        item_created DATETIME,
        item_edited DATETIME,


CREATE TABLE #ITEMS_EDITED (item_Id BIGINT,
        item_name VARCHAR(100),
        item_number_of_items INT,
        item_created DATETIME,
        item_edited DATETIME,


CREATE TABLE #ITEMS_DELETED (item_Id BIGINT,
        item_name VARCHAR(100),
        item_number_of_componentns INT,
        item_created DATETIME,
        item_edited DATETIME,item_deleted DATETIME,



DECLARE @SELECTDATE DATETIME 
SET @SELECTDATE = '2013/05/29' 
DECLARE @PRODUCT_ID UNIQUEIDENTIFIER
SET @PRODUCT_ID = 'F67A7F31-6031-4213-8826-E53E1BC21337'


INSERT INTO #ITEMS_CURENTSTATE

SELECT item_Id,
    item_name,
    item_number_of_items,
    item_created,
    item_edited,
    FROM item WHERE 
PRODUCT_ID=@PRODUCT_ID 
AND FLOOR(CAST (ISNULL(item_edited,item_created) AS FLOAT)) <= FLOOR(CAST(@SELECTDATE AS FLOAT))





INSERT INTO #ITEMS_DELETED

SELECT item_Id,
        item_name,
        item_number_of_items,
        item_created,
        item_edited,item_deleted,


     FROM History WHERE PRODUCT_ID=@PRODUCT_ID AND FLOOR(CAST(item_deleted AS FLOAT)) <= FLOOR(CAST(@SELECTDATE AS FLOAT))



INSERT INTO #ITEMS_EDITED

SELECT  item_Id,
        item_name,
        item_number_of_items,
        item_created,
        item_edited,
     FROM History WHERE PRODUCT_ID=@PRODUCT_ID AND item_Id NOT IN (SELECT item_Id FROM #ITEMS_CURENTSTATE UNION ALL SELECT item_Id FROM #ITEMS_DELETED)
    AND FLOOR(CAST (ISNULL(item_edited,item_created) AS FLOAT)) <= FLOOR(CAST(@SELECTDATE AS FLOAT)) 



    SELECT * FROM #ITEMS_CURENTSTATE

   UNION ALL


    SELECT  A.item_Id,
        A.item_name,
        A.item_number_of_items,
        A.item_created,
        A.item_edited,
         FROM (SELECT item_Id,MAX(ISNULL(item_edited,CAST(0 AS DATETIME))) AS MaxEditDate FROM #ITEMS_EDITED GROUP BY item_Id) B 
        INNER JOIN #ITEMS_EDITED A ON A.item_Id=B.item_Id AND ISNULL(A.item_edited,CAST(0 AS DATETIME))=B.MaxEditDate


    DROP TABLE #ITEMS_CURENTSTATE    
    DROP TABLE #ITEMS_DELETED
    DROP TABLE #ITEMS_EDITED
于 2013-05-29T16:04:23.527 回答