SQL从项目到所有者表中选择所有者的所有项目

问题描述:

我有一个表bike_to_owner。我想选择特定用户拥有的当前项目。SQL从项目到所有者表中选择所有者的所有项目

表结构

CREATE TABLE IF NOT EXISTS `bike_to_owner` (
    `bike_id` int(10) unsigned NOT NULL, 
    `user_id` int(10) unsigned NOT NULL, 
    `last_change_date` date NOT NULL, 
    PRIMARY KEY (`bike_id`,`user_id`,`last_change_date`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

在用户的个人资料页,我想显示所有他/她当前的财产。

我写了这样一句话:

SELECT `bike_id`,`user_id`,max(last_change_date) FROM `bike_to_owner` 
WHERE `user_id` = 3 group by `last_change_date` 

,但我不能肯定它正常工作在所有情况下。 你可以请确认这是正确的,如果不是建议我更好的东西。 使用php/mysql。

在此先感谢!

+1

基于Eric的回答下的讨论,您能否提供一些示例数据以及您希望查询返回的数据的样例? – 2010-06-03 17:42:34

+0

借调菲利普的评论。如果您提供了一些样本数据,其中我提供的答案没有给出正确的结果,并且您希望获得正确的结果,我们可能可以帮助您更好一些。 – 2010-06-03 19:34:59

+0

好的,这里有一些示例数据。 INSERT INTO'bike_to_owner'('bike_id','user_id','last_change_date')值 (1,1,'2009-01-01'), (1,3,'2009-11-10') , (3,3,'2009-02-13'), (3,5,'2010-05-11'), (5,'2010-06-04'); 我希望用户1只拥有自行车1,用户1不具备在所有自行车和用户5到自己的自行车3和5 – kdobrev 2010-06-04 10:11:33

在您的意见光,我将只给出新的答案在这里。

既然你可以有用户采取的自行车的所有权,然后放弃它,然后再次得到它,你希望能够追踪历史,我建议你的方案略有变化:

CREATE TABLE IF NOT EXISTS `bike_to_owner` (
    `bike_id` int(10) unsigned NOT NULL, 
    `user_id` int(10) unsigned NOT NULL, 
    `acquired_date` date NOT NULL, 
    `sold_date` date NULL, 
    PRIMARY KEY (`bike_id`,`user_id`,`acquired_date`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

每当自行车转手,你会更新sold_date前拥有当前的日期和为NULL sold_date和当前日期的acquired_date新东家创造一个新的记录。

然后你的查询,以确定目前的所有权应该是这样的:

SELECT `bike_id`,`user_id` FROM `bike_to_owner` 
WHERE `user_id` = 3 AND sold_date IS NULL 
+0

你有一点。另一方面,你的方式使得数据库没有被标准化,因为每个'sold_date'都将是新的拥有者'acquire_date'。虽然,select语句是2143232523542次更简单。 那哪个更好?我会坚持我以前的设计,以便不会对我已经编写的代码进行其他更改,但是如果您有一些有力的论据,我会进行更改。 – kdobrev 2010-06-04 12:51:25

+0

@kdobrev - 我不会说它没有正常化。这是一种非常普遍的模式。它还允许将自行车出售给不是用户的人(或者例如自行车被盗或销毁)的概念。使用您现有的模型,停止拥有自行车的唯一方法是将其出售给其他用户。不过,如果您对此有所担忧,可以用'active'或'current'位列代替'sold_date'并以同样的方式使用它。使用'sold_date'可以提供比位列更多的信息,并使其他潜在的查询更容易。 – 2010-06-04 12:57:33

+0

我的模型跟踪交易,而此模型跟踪用户和自行车之间的关系(随着时间的推移)。两种模式都适用。您使用的最终模型基于您正在构建的系统的已知(和预期)要求。 – 2010-06-04 14:16:02

快到了,但是你应该bike_id和USER_ID被分组,而不是上次更改日期:

SELECT `bike_id`,`user_id`,max(last_change_date) FROM `bike_to_owner` 
WHERE `user_id` = 3 group by `bike_id`, `user_id` 

ETA:

顺便说一句,我很好奇,为什么你有最后的更改日期在该表中作为关键的一部分。一辆自行车可以在不同的更改日期多次与用户关联吗?如果是这样,为什么?我认为自行车既可以与用户相关联,也可以不与用户相关联 - 除了添加或删除关系之外,没有任何东西可以“改变”。除非在桌子上还有其他的字段没有显示?

+0

首先回答你的问题。这是一个自行车登记册。所以自行车是真实世界的自行车,用户是真实的人。人们把自行车卖给对方,自行车在系统中保持不变。因此,所有者的变化不会超过每天一次。有人很少有机会购买旧的,以前卖过的自行车。显示的表格结构是整个表格,不再有字段。 不幸的是,我的和Eric的两个语句都没有返回正确的值。 – kdobrev 2010-06-03 16:44:50

+0

我不坚持这种表格结构,这只是我认为最好的方式。如果你能提出更好的建议,我会很乐意使用它。 – kdobrev 2010-06-04 11:06:03

这里是工作的声明:

SELECT t1.* 
FROM bike_to_owner t1 
LEFT JOIN bike_to_owner AS t2 ON t1.bike_id = t2.bike_id 
AND t1.last_change_date < t2.last_change_date 
WHERE t2.last_change_date IS NULL 
AND t1.user_id = 3 

我想了很多取决于你试图存储,并能够从数据库中检索的信息。试图第二猜测这一点,我想提出以下组表(请注意,只有在这些表中的一列允许空值):

-- User ----- 
user_id (primary key) 
name 

-- Bike ------ 
bike_id (primary key) 
description 
current_owner nullable (foreign key to User) 

这假定“自行车所有权”是一个临界指数以及经常需要的信息,并且值得向该结构添加非规范化数据以使得找到自行车的当前用户或用户当前的自行车无关紧要。 (添加非规范化数据的一个关键原因是简化数据检索和/或提高性能。在您制作的每个查询中跳过制定销售历史记录都可以。)如果所有权持续时间很重要,则可以添加“purchased_on”列,或者深入查看事务表。

要跟踪当自行车被购买:

-- Bike_Purchase ------ 
user_id (foreign key to User) 
bike_id (foreign key to Bike) 
purchased_on 
(primary key on all three columns) 

将跟踪每一个用户购买了自行车的时间。相反,如果当自行车卖给你宁愿跟踪,你可以有

-- Bike_Sale ------ 
user_id (foreign key to User) 
bike_id (foreign key to Bike) 
sold_on 
(primary key on all three columns) 

同时跟踪购买和销售,包括无论是两个表或一个简单的企业集团:

-- Bike_Transaction ------ 
user_id (foreign key to User) 
bike_id (foreign key to Bike) 
transaction_type ** 
transaction_date 
(primary key on all four columns) 

这可以让你准确地跟踪您的用户的购买和销售,并忽视非用户的交易。卖了一辆自行车?输入一个条目。不知道或关心他们卖给谁?不要输入。

无论您使用哪个时间跟踪表,确定持续时间与加入(user_id,bike_id)和获取max(日期)一样简单。把给定的自行车的“所有权链”,或者自己拥有的自行车和什么时间/多长时间组合在一起将是棘手的,但是完全可行。

**对于transaction_type,您可能需要设置一个Transaction_Type表来跟踪不同的交易(出售,购买,交易,发现,丢失/被盗等等)。或者,您可以使其成为一个varchar一个描述性的字符串,或者放一个CHECK约束来限制它到选定的值。