2010-06-03 157 views
0

我有一個表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

回答

1

在您的意見光,我將只給出新的答案在這裏。

既然你可以有用戶採取的自行車的所有權,然後放棄它,然後再次得到它,你希望能夠追蹤歷史,我建議你的方案略有變化:

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

1

快到了,但是你應該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

0

這裏是工作的聲明:

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 
0

我想了很多取決於你試圖存儲,並能夠從數據庫中檢索的信息。試圖第二猜測這一點,我想提出以下組表(請注意,只有在這些表中的一列允許空值):

-- 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約束來限制它到選定的值。