データベースの設計 :
フィドル: http://sqlfiddle.com/#!2/4f23b3
私はテーブルを持っていますplayers
CREATE TABLE players (
id MEDIUMINT(7) unsigned AUTO_INCREMENT PRIMARY KEY ,
name VARCHAR(30)
) ENGINE = InnoDB
テーブルobjects
CREATE TABLE objects (
id INT(9) unsigned AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30),
type VARCHAR(20)
) ENGINE = InnoDB
そして、one-to-many
オブジェクトとプレーヤーの関係を説明する表 (プレーヤーは複数のオブジェクトを持つことができます) ですが、one-to-many
後で説明するように厳密ではありません:
CREATE TABLE playerobjects (
objectid INT(9) unsigned NOT NULL,
playerid MEDIUMINT(7) unsigned NOT NULL,
`date` DATE NOT NULL,
PRIMARY KEY(objectid,`date`)
) ENGINE = InnoDB
上の表はわかりにくいかもしれませんが、すべての意味は次のとおりです。
- プレーヤーは、特定の日付に多くのオブジェクトを持つことができます
- オブジェクトは、特定の日付に 1 人のプレーヤーにのみ属することができます
- プレイヤーは別のプレイヤーからオブジェクトを盗む
playerobjects
ことができます。これは、盗まれたオブジェクトに対して、異なるプレイヤー ID と異なる日付を持つ 2 つのエントリがテーブルにあることを意味します。 - オブジェクトは 1 日に 1 回だけ盗むことができます
したがって、上記のガイドラインから、オブジェクトには多くの所有者がいる可能性がありますが、1 日に 1 人だけであると推測できます。また、プレーヤー 1 がプレーヤー 2 からオブジェクトを盗み、翌日、プレーヤー 2 がプレーヤー 1 からオブジェクトを盗む可能性もあります。
私がしたいこと :
さて、上記のデータベースから、プレイヤーが盗んだオブジェクトの数と、現在所有しているオブジェクトの数を調べたいと思います。また、トッププレイヤーを順番に表示するリーダーボードを作りたいです。盗品の。
つまり、ボブが最初にオブジェクトを持っていたが、エミリーがボブからそれを盗み、シェルドンがエミリーから盗んだ場合、エミリーはボブからオブジェクトを盗んだがそれはずっと前のことで、オブジェクトの現在の所有者は Sheldon です。
サンプルコード
INSERT INTO players (name) VALUES ('Bob') , #id 1
('Emily') , #id 2
('Sheldon'); #id 3
INSERT INTO objects (name,type) VALUES ('Choco vanilla','ice cream'), #1
('Butterscotch','ice cream'), #2
('Nexus 4','Mobile Phone'), #3
('Snoopy','pet'), #4
('minecraft','game'); #5
INSERT INTO playerobjects (playerid,objectid,date) VALUES (1,1,'2013-05-15'),
(2,2,'2013-05-15'),
(3,3,'2013-05-15'),
(1,4,'2013-05-15'),
(2,1,'2013-05-16'),
(1,5,'2013-05-16'),
(3,1,'2013-05-17'),
(1,3,'2013-05-18'),
(3,3,'2013-05-19'),
(3,5,'2013-05-19'),
(2,5,'2013-05-20');
ID 3、rows の個人の期待される結果:
(3,1,'2013-05-17'),
(3,3,'2013-05-19')
ID 2、行 の個人の期待される結果:
(2,5,'2013-05-20')
プレーヤー 1 の期待される結果: なし。盗んだオブジェクトが再び盗まれ、誰からも盗まれなかったオブジェクトだけが残されたためです。
リーダーボード クエリの期待される結果:
sheldon 2
emily 1
bob 0
私が思いついたもの:
リーダーボードのクエリは、間違った情報を提供し、非効率的だと思います:
SELECT tpo.playerid,COUNT(*) as steals
FROM `playerobjects` AS tpo
LEFT JOIN `playerobjects` AS tpo2 ON (tpo.objectid = tpo2.objectid AND tpo.date < tpo2.date)
LEFT JOIN `playerobjects` AS tpo3 ON (tpo.objectid = tpo3.objectid AND tpo.date > tpo3.date)
WHERE tpo2.objectid IS NULL
AND tpo3.objectid IS NOT NULL
GROUP BY (tpo.playerid)
ORDER BY steals DESC
個々のプレイヤーと盗みに関する詳細情報のクエリを実行すると、間違った情報が返されます。
SELECT tpo.objectid,tpo.date
FROM `playerobjects` AS tpo
LEFT JOIN `playerobjects` AS tpo2 ON (tpo.objectid = tpo2.objectid AND tpo.date < tpo2.date)
LEFT JOIN `playerobjects` AS tpo3 ON (tpo.objectid = tpo3.objectid AND tpo.date > tpo3.date)
WHERE tpo2.objectid IS NULL
AND tpo3.objectid IS NOT NULL
これらのクエリが間違った情報を返すのはなぜですか? オブジェクトの以前のレコードもカウントするためです。これを前の Bob Emily Sheldon の例と関連付けると、Sheldon が Emily からオブジェクトを盗んだときのレコードのみが返されるはずですが、Emily が Bob からオブジェクトを盗んだレコードも表示されます。クエリをさらに非効率にする複雑なサブクエリを使用せずにこれを修正する方法がわかりません。これを行うためのより良い方法があることを本当に願っています。