如何在sql表中获取以前的所有者?

Posted

技术标签:

【中文标题】如何在sql表中获取以前的所有者?【英文标题】:How to get previous owner in sql table? 【发布时间】:2009-09-28 22:27:00 【问题描述】:

我有一个交易表(transId、sn、customerId、日期),其中列出了客户之间的项目交易。某些物品具有 sn(序列号)并从一个客户转移到另一个客户。对于某些客户 (12345678),我需要找出谁是客户物品的最后一个所有者。

这是我的查询:

   SELECT c.*, 
          p.transId, 
          p.customerId
     FROM Transaction c 
LEFT JOIN Transaction p ON c.sn = p.sn
    WHERE p.transId = (SELECT MAX(t.transId) 
                         FROM Transaction t 
                        WHERE t.transId < c.transId 
                          AND t.sn = c.sn)
     AND c.customerId = 12345678
ORDER BY p.transId;

此查询工作正常,除非项目没有以前的所有者。应该为 p.transId 和 p.customerId 返回空值,但它返回 0 行。数据库是Access

更新:我需要 BOTH 在结果中包含当前所有者和以前的所有者(在一行中)。而且,它应该适用于中间所有者(如日志;如果客户不是当前所有者,但之前是所有者)。

更新:对于某些客户(这将作为参数传递;在我们的例子中 customerId=12345678),我需要查看他曾经拥有的所有物品的列表以及最后一个所有者物品的数量(他从哪个客户那里得到了物品)。

更多解释:

transId 是主键和自动编号(身份) - 以前的所有者的 transId 将小于新所有者的 transId 交易中的客户 ID 是买方(该交易后的新所有者) 日期不包含时间;仅日期(不应用于比较或订购,因为某些商品可以在一天内更换两个所有者)

这里有一个小例子,可以让事情更清楚(日期未显示):

事务表 ---------------------- |transId|sn|customerId| | 1| 1| 12345678| | 2| 2| 87654321| | 3| 2| 12345678| | 4| 2| 11223344| | 5| 2| 12345678| ---------------------- 对于 customerId=12345678 结果应该是 结果 -------------------------------------------------- |transId|sn|customerId|prevTransId|prevCustomerId| | 1| 1| 12345678|空|空| | 3| 2| 12345678| 2| 87654321| | 5| 2| 12345678| 4| 11223344| --------------------------------------------------

【问题讨论】:

你要么写错了作业,要么你没有足够准确地传达问题。是否“对于 customerID 12345678 曾经拥有的任何物品 (sn),找到拥有该物品的当前所有者 (customerID) - 可能不再是 customerID 12345678 - 以及任何其他也拥有该物品的人”?这与“中间所有者”是一致的。还是“找到我当前的所有者(不一定是 customerID 12345678)和将这件作品出售到 customerID 12345678 的所有者”?这是一个讨厌的查询,并且不包括中间所有者。 ...或者...嗯,还有其他可能的解释。另一个问题:交易表是否记录了该物品的销售者或购买者(事实上,如果同时记录该物品的销售者和购买者,这不是更正常吗)?此外,日期列的粒度是多少 - 它记录年/月/日还是包括时间?一件商品能否在一个日期内多次出售(如果包括时间,则可能不会;如果仅包括年/月/日,则可能)?我们是否有权假设 transID 随时间单调增加? 如果您需要的是任何曾经拥有过 customerID 12345678 曾经拥有过的商品的任何人的 customerID,这并不难,即使您想知道另一个商品的 SN客户拥有。 @Jonathan:感谢您的 cmets。我已经更新了这个问题。我希望现在更清楚了。这是我从事的一个自定义项目,因此我可以在需要时更改数据库模式(不幸的是,我的上学时间结束了:()。考虑到您的问题是否应将卖方和买方放在同一行中;我考虑了一下,但这将是多余的信息(例如,如果您需要删除一些中间事务,则必须删除该行并更新下一行的先前所有者)。只有在当前模式无法解决问题的情况下,我才会添加. 【参考方案1】:

p.transId = ... 的条件从 WHERE 子句移到 JOIN 条件中(在任何情况下您都不需要c.sn = p.sn):

普通 SQL:

   SELECT c.*, 
          p.transId, 
          p.customerId
     FROM Transaction c 
LEFT JOIN Transaction p 
       ON p.transId = (SELECT MAX(t.transId) 
                         FROM Transaction t 
                        WHERE t.transId < c.transId 
                          AND t.sn = c.sn)
    WHERE c.customerId = 12345678
ORDER BY p.transId;

MS Access SQL:

SELECT      c.*, 
            p.transId, 
            p.customerId
FROM        Transaction c 
LEFT JOIN ((SELECT  t.transId, MAX(z.transId) AS PrevTransId
            FROM    Transaction t 
            LEFT JOIN Transaction z on t.sn = z.sn
            WHERE   z.transId < t.transId 
            GROUP BY t.transId) x
LEFT JOIN   Transaction p ON p.TransId = x.PrevTransId
           ) ON  x.TransId = c.TransId
WHERE       c.customerId = 12345678
ORDER BY    p.transId;

【讨论】:

我已经尝试过(之前和现在),但 Access 报告:“查询表达式中的语法错误 'p.transId = (SELECT MAX(t.transId)...'。”。跨度> @BB:还添加了 MS-Access 版本 - brrrr,丑陋。

以上是关于如何在sql表中获取以前的所有者?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 SQL Server 中特定数据库的表中获取所有列名?

如何操作SQL IN运算符以返回所有值作为结果

如何从加载在 sql/plsql 表中的 csv 文件中获取值

如何获取在 SQL Server 内部数据库的不同表中重复的列[重复]

如何在sql server中通过给定的邮政编码和以英里为单位的半径从附近的表中获取所有其他邮政编码或(纬度和经度)?

如何使用 pl sql 过程从结构仅在运行时知道的 oracle 表中动态获取数据?