在Access中连接多个表并限制为Top 1结果

时间:2014-06-20 15:03:12

标签: sql ms-access-2013

我有三个表需要加入才能获得每月的库存数据。

表1:TargetInventory
表2:TargetValue
表3:TargetWeight

[TargetInventory]在第一次添加后不会改变。

[TargetValue]只是一张包含各种金属价格的小桌子。

[TargetWeight]每月更新一次,作为我们库存流程的一部分。我们INSERT新数据,我们永远不会更新旧数据。

以下是这些表之间的关系。 (对不起,我没有信誉点发布图片。全新的,所以希望这是有道理的。)

(* = UniqueKey)

--TargetValue--      --TargetInventory--  --TargetWeight--
*MaterialID <===|    *TargetID <=====|    *ID
 Material       |===> MaterialID     |===> TargetID
 PricePerOunce        Length               RecordDate
 Density              Width                Weight
                      Thickness
                      DateInInventory

TargetWeight表包含TargetID的多个记录(因为每个月都会在库存中添加一个新记录)。这对跟踪历史使用情况有好处,但对于当前库存值,我只需要返回最新的TargetWeight.Weight。

我不知道如何在另一个INNER JOIN中进行交叉应用,所以我不知道如何做到这一点(没有切换到mySQL,只是做了LIMIT 1 ... )

我认为它需要看起来像下面的内容,但我不确定如何完成查询。

SELECT
TargetInventory.TargetID AS TargetInventory_TargetID, 
TargetInventory.MaterialID AS TargetInventory_MaterialID, 
TargetInventory.Length, 
TargetInventory.Width, 
TargetInventory.Thickness, 
TargetValue.MaterialID AS TargetValue_MaterialID, 
TargetValue.PricePerOunce, 
TargetValue.Density, 
TargetWeight.ID, 
TargetWeight.TargetID AS TargetWeight_TargetID, 
TargetWeight.RecordDate, 
TargetWeight.Weight
FROM
(TargetValue 
    INNER JOIN TargetInventory 
    ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
CROSS APPLY (
     SELECT TOP 1 *
     FROM .....
)

2 个答案:

答案 0 :(得分:2)

以下查询适用于Access 2010.它使用子查询上的INNER JOIN代替CROSS APPLY(Access SQL不支持)。它假定给定(TargetID,RecordDate)的记录不会超过一个[TargetWeight]:

SELECT 
    TargetInventory.TargetID AS TargetInventory_TargetID, 
    TargetInventory.MaterialID AS TargetInventory_MaterialID, 
    TargetInventory.Length, 
    TargetInventory.Width, 
    TargetInventory.Thickness, 
    TargetValue.MaterialID AS TargetValue_MaterialID, 
    TargetValue.PricePerOunce, 
    TargetValue.Density, 
    LatestWeight.ID, 
    LatestWeight.TargetID AS TargetWeight_TargetID, 
    LatestWeight.RecordDate, 
    LatestWeight.Weight
FROM 
    (
        TargetValue 
        INNER JOIN 
        TargetInventory 
            ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
    ) 
    INNER JOIN 
    (
        SELECT tw.*
        FROM
            TargetWeight AS tw
            INNER JOIN
            (
                SELECT TargetID, MAX(RecordDate) AS LatestDate
                FROM TargetWeight
                GROUP BY TargetID
            ) AS latest
                ON latest.TargetID=tw.TargetID
                    AND latest.LatestDate=tw.RecordDate
    ) AS LatestWeight
        ON LatestWeight.TargetID = TargetInventory.TargetID

专门针对Access 2010或更高版本的替代方法

如果上面的查询在[TargetWeight]中遇到大量行,那么Access 2010+的另一个可能解决方案是将名为[Current]的Yes/No字段添加到[TargetWeight]表并使用以下插入数据宏之后,确保只将每个[TargetID]的最新记录标记为[Current]:

AfterInsert.png

完成后,查询将只是

SELECT 
    TargetInventory.TargetID AS TargetInventory_TargetID, 
    TargetInventory.MaterialID AS TargetInventory_MaterialID, 
    TargetInventory.Length, 
    TargetInventory.Width, 
    TargetInventory.Thickness, 
    TargetValue.MaterialID AS TargetValue_MaterialID, 
    TargetValue.PricePerOunce, 
    TargetValue.Density, 
    TargetWeight.ID, 
    TargetWeight.TargetID AS TargetWeight_TargetID, 
    TargetWeight.RecordDate, 
    TargetWeight.Weight
FROM 
    (
        TargetValue 
        INNER JOIN 
        TargetInventory 
            ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
    ) 
    INNER JOIN 
    TargetWeight 
        ON TargetInventory.TargetID = TargetWeight.TargetID
WHERE TargetWeight.Current = True;

为了最大限度地提高性能,应将[TargetWeight]。[TargetID]和[T​​argetWeight]。[Current]字段编入索引。

答案 1 :(得分:0)

SELECT      TargetInventory.TargetID AS TargetInventory_TargetID, 
            TargetInventory.MaterialID AS TargetInventory_MaterialID, 
            TargetInventory.Length, 
            TargetInventory.Width, 
            TargetInventory.Thickness, 
            TargetValue.MaterialID AS TargetValue_MaterialID, 
            TargetValue.PricePerOunce, 
            TargetValue.Density,        Weight.ID, 
            Weight.TargetID AS TargetWeight_TargetID,
            Weight.RecordDate, 
            Weight.Weight
FROM        TargetInventory
INNER JOIN  TargetValue ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
CROSS APPLY (
                SELECT TOP 1 *
                FROM    TargetWeight
                WHERE   TargetID = TargetInventory.TargetID
                ORDER BY RecordDate DESC
            )   AS Weight