sql子查询并加入一对多表

时间:2012-10-30 12:23:14

标签: sql sql-server-2008 join subquery one-to-many

这个让我头疼得厉害!基本上,我需要显示一个位置列表,存储在那里的当前项目以及拥有它的人。我创建了4个表,并填充了数据。

设置:MSSQL 2008

我正在寻找的是来自物品和所有者的tbl_locationHistory的“Top(1)”,因为在每个位置任何时候都只能有一个物品或一个物主。请记住,tbl_locationHistory可能有多位数据,我只需要为每一位提取最新的ID(例如,最高的ownerID,历史表中当前可用的最高itemID)。

tbl_location

LOCID LOCNAME

tbl_item

ITEMID ITEMNAME

tbl_owner

OWNERID OWNERNAME

tbl_locationHistory

locHistID LOCID ITEMID OWNERID dateModified

我尝试将所有这些表与连接一起加入。但是我意识到这不起作用,因为我没有撤回“所有者”或“项目”的顶部ID,因此显示的数据将是不准确的。

我想到的一件事是我应该将历史表分成两部分:1 x所有者到位置和1 x项到位 - 但是我现在处于SQL的极限,所以可以用一些指针来做正确的方向,因为不知道采用哪种方式。

因此,即使我必须打破历史记录表,我也需要帮助。

更新01/11/12

好的,我将在这里粘贴一些代码。

我是一个古老的学校经典ASP编码器.....还没有必要继续前进!我使用经典的asp和MSSQL来创建这个应用程序。我也使用Dreamweaver,因此希望将查询放在那里,这样我就可以使用DW CS6中的“绑定”功能了。

这是我原来的疑问:

SELECT DISTINCT p.pID, p.cliID, p.pNo, p.pName, p.dtCommissioned,     
p.description, ps.plotStatus, pt.plotType, o.oSalutation, o.oFname, o.oSname, man.manName, 
mod.model, sl.width, sl.length, sl.yr
FROM history AS ph INNER JOIN owners AS o ON ph.ownerID   
= o.ownerID INNER JOIN StockList AS sl ON ph.stockID = sl.stkID   
INNER JOIN manufacturers AS man ON sl.make = man.manID 
INNER JOIN models AS mod ON sl.model = mod.cID FULL OUTER   
JOIN plotType AS pt RIGHT OUTER JOIN                       
plots AS p ON pt.plotTypeID = p.plotType LEFT OUTER JOIN                       
plotStatus AS ps ON p.pStatus = ps.plotStatusID ON ph.plotID = p.pID
WHERE (p.cliID = value)
ORDER BY p.pNo

现在,当我意识到我没有正确查看历史表中的“stockID”的最高HistoryID以及“ownerID”的最高plotHistoryID时,我开始研究如何执行“子查询”每个ID ......这就是我被困住的地方。

我尝试了以下方面的内容:

Select p.pID, p.cliID, p.pNo, p.pName, p.dtCommissioned,     
p.description, ps.plotStatus, pt.plotType, o.oSalutation, o.oFname, o.oSname, man.manName, 
mod.model, sl.width, sl.length, sl.yr
(Select top 1 ph.plotHistoryID, ownerID
FROM History AS ph
order by ph.plotHistoryID desc)
THEN JOINING ETC
THEN DO ANOTHER SUBQUERY FOR THE OWNER ETC

但是我无法让它工作,但我现在超出了与Sub Queries和JOINS相关的SQL级别。

输出显示将是:

情节编号|剧情名称|情节类型|情节状态|现任主人|当前股票

每个Plot No / Names / Type / Status都会填充数据,因为我需要显示它们。如果所有者\当前股票是空白的,我有一个IF声明说“没有所有者”或“没有找到股票”。

然后,用户可以点击行末的“查看”链接并查看地图/位置的详细信息,并通过QueryString将pID传递到下一页。

这有帮助吗?我现在变得有点绝望了! LOL

1 个答案:

答案 0 :(得分:0)

您可以使用ROW_NUMBER功能来帮助仅获取每个位置的最新历史记录事件,然后使用此功能重新加入所有者和项目:

WITH LocationHistoryExt AS
(   SELECT  LocID, 
            ItemID, 
            OwnerID,
            DateModified,
            [RowNumber] = ROW_NUMBER() OVER(PARTITION BY LocID ORDER BY DateModified DESC)
    FROM    tbl_LocationHistory
)
SELECT  l.LocName,
        i.ItemID,
        o.OwnerName,
        lh.DateModified
FROM    tbl_Location l
        INNER JOIN LocationHistoryExt lh
            ON l.LocID = lh.LocID
            AND RowNumber = 1 -- ONLY LATEST EVENT
        INNER JOIN tbl_Item i
            ON lh.ItemID = i.ItemID
        INNER JOIN tbl_Owner o
            ON o.OwnerID = lh.OwnerID

编辑 - 添加说明

顶部是Common table Expression (CTE),在这种情况下,它只是将子查询移出主查询的一种方式,所以

WITH CTE AS
(   SELECT  A, B, C
    FROM    T
)
SELECT  *
FROM    CTE

与执行

完全相同
SELECT  A, B, C
FROM    T

CTE中的ROW_NUMBER将为每个历史事件分配一个行号,具体取决于其中的ORDERPARTITION子句,因此在tbl_LocationHistory中给出以下示例数据:

locHistID | locID | itemID | ownerID | dateModified
----------+-------+--------+---------+--------------
    1     |   1   |   1    |   1     |  20121001
    2     |   1   |   4    |   2     |  20121002
    3     |   1   |   3    |   1     |  20121003  <-- LATEST FOR LocID 1
    4     |   2   |   5    |   2     |  20121002
    5     |   2   |   1    |   2     |  20121004
    6     |   2   |   2    |   3     |  20121005  <-- LATEST FOR LocID 2

我假设您要做的是检索每个位置ID的最新行,并获取与该行关联的itemID和OwnerID,因此解构ROW_NUMBER函数:

ROW_NUMBER() OVER(PARTITION BY LocID ORDER BY DateModified DESC);

这将为您的数据中的每一行分配一个行号,每个LocIDPARITION BY locID)再次从1开始,它将从具有最新修改日期的记录开始编号为1({ {1}})。将其应用于您将获得的样本数据:

ORDER BY DateModified DESC

这是我在查询中在CTE中重新检索的内容,然后当我加入它时,我添加了locHistID | locID | itemID | ownerID | dateModified | RowNumber ----------+-------+--------+---------+--------------+--------------- 1 | 1 | 1 | 1 | 20121001 | 3 2 | 1 | 4 | 2 | 20121002 | 2 3 | 1 | 3 | 1 | 20121003 | 1 4 | 2 | 5 | 2 | 20121002 | 3 5 | 2 | 1 | 2 | 20121004 | 2 6 | 2 | 2 | 3 | 20121005 | 1 ,这意味着只返回最新的行

RowNumber = 1

剩余部分只是正常连接,以从上面的2行获取适当的位置,所有者和项目。

我希望现在更有意义。如果不让我知道,我会尝试并解释其他任何一点。

编辑2 - 空字段的会计

我稍微更改了选择的顺序,并将FROM tbl_Location l INNER JOIN LocationHistoryExt lh ON l.LocID = lh.LocID AND RowNumber = 1 -- ONLY LATEST EVENT locHistID | locID | itemID | ownerID | dateModified | RowNumber ----------+-------+--------+---------+--------------+--------------- 3 | 1 | 3 | 1 | 20121003 | 1 6 | 2 | 2 | 3 | 20121005 | 1 更改为INNER JOIN,但主体仍然相同:

LEFT JOIN