0

現在、私はプレーヤーの最後の転送を一覧表示するオンライン ゲームを作成しています。

プレーヤーの履歴を処理するテーブルには、列 history_join_date と history_end_date があります。

history_end_date が満たされている場合は、プレイヤーがクラブを離れたことを意味し、デフォルト (0000-00-00 00:00:00) のように history_join_date に何らかの日付がある場合は、プレイヤーが (その日付で) クラブに参加したことを意味します。

現在、次のクエリがあります。

SELECT 
    player_id,
    player_nickname,
    team_id,
    team_name,
    history_join_date,
    history_end_date
FROM 
    players
        INNER JOIN history
            ON history.history_user_id = players.player_id
        INNER JOIN teams
            ON history.history_team_id = teams.team_id
ORDER BY 
    history_end_date DESC, 
    history_join_date DESC
LIMIT 7

ただし、このクエリは次のようなものを返します (上記の PHP でフィルタリング):

(22-Aug-2012 23:05): Folha has left Portuguese Haxball Team.
(22-Aug-2012 00:25): mancini has left United.
(21-Aug-2012 01:29): PatoDaOldSchool has left Reign In Power.
(22-Aug-2012 23:37): Master has joined Born To Win.
(22-Aug-2012 23:28): AceR has joined Born To Win.
(22-Aug-2012 23:08): Nasri has joined Porto Club of Haxball.
(22-Aug-2012 18:53): Lloyd Banks has joined ARRIBA.

PHP フィルター:

foreach ($transfers as $transfer) {

//has joined
if($transfer['history_end_date']<$transfer['history_join_date']) {
    $type = ' has joined ';
    $date = date("d-M-Y H:i", strtotime($transfer['history_join_date']));
} else {
    $type = ' has left ';
    $date = date("d-M-Y H:i", strtotime($transfer['history_end_date']));
}

ご覧のとおり、転送順序では、日付は厳密には守られていません (8 月 22 日 => 8 月 21 日 => 8 月 22 日)。

SQL に欠けているものは何ですか?

よろしく!

4

2 に答える 2

1

問題は、2 つの異なる値に基づいて注文していることです。したがって、結果は最初に history_end_date で並べ替えられ、終了日が同じ場合 (つまり、デフォルト値の場合)、次に history_join_date で並べ替えられます。

(最初の結果はすべて終わりであり、その後の結果はすべて結合であり、各サブセットは適切に並べられていることに注意してください)。

このデータ構造をどの程度制御できますか? 日付が 1 つしかなく、履歴タイプが JOINED または END になるように履歴テーブルを再構築できる場合があります。


質問の内容から、次の DDL とデータを作成しました。

create table players (
    player_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    player_nickname VARCHAR(255) NOT NULL UNIQUE
);

create table teams (
    team_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    team_name VARCHAR(255) NOT NULL UNIQUE
);

create table history (
    history_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    history_user_id INT NOT NULL, history_team_id INT NOT NULL, 
    history_join_date DATETIME NOT NULL, 
    history_end_date DATETIME NOT NULL DEFAULT "0000-00-00 00:00:00"
);

insert into players VALUES 
    (1,'Folha'),
    (2,'mancini'),
    (3,'PatoDaOldSchool'),
    (4,'Master'),
    (5,'AceR'),
    (6,'Nasri'),
    (7,'Lloyd Banks');

insert into teams VALUES 
    (1,'Portuguese Haxball Team'),
    (2,'United'),
    (3,'Reign In Power'),
    (4,'Born To Win'),
    (5,'Porto Club of Haxball'),
    (6,'ARRIBA');

insert into history VALUES 
    (DEFAULT,1,1,'2012-08-01 00:04','2012-08-22 23:05'),
    (DEFAULT,2,2,'2012-08-21 19:04','2012-08-22 00:25'),
    (DEFAULT,3,3,'2012-08-19 01:29','2012-08-21 01:29'),
    (DEFAULT,4,4,'2012-08-22 23:37',DEFAULT),
    (DEFAULT,5,4,'2012-08-22 23:28',DEFAULT),
    (DEFAULT,6,5,'2012-08-22 23:08',DEFAULT),
    (DEFAULT,7,6,'2012-08-22 18:53',DEFAULT);

解決策 1 - 履歴イベント ビュー

これが唯一の解決策ではないことは明らかです (必要に応じてオプションを評価する必要がありますが、MySQL で履歴イベントのビューを作成し、それに参加して、次のような順序付けに使用できます。

create view historyevent (
    event_user_id,
    event_team_id,
    event_date,
    event_type
) AS
    SELECT 
        history_user_id,
        history_team_id,
        history_join_date,
        'JOIN' 
    FROM history
    UNION
    SELECT
        history_user_id,
        history_team_id,
        history_end_date,
        'END'
    FROM history 
    WHERE history_end_date <> "0000-00-00 00:00:00";

あなたの選択は次のようになります:

SELECT 
    player_id,
    player_nickname,
    team_id,
    team_name,
    event_date,
    event_type
FROM players
INNER JOIN historyevent
        ON historyevent.event_user_id = players.player_id
INNER JOIN teams
        ON historyevent.event_team_id = teams.team_id
ORDER BY 
    event_date DESC;

ここでの利点は、同じプレイヤーの参加と脱退の両方を取得できることです。


解決策 2 - 疑似列。IF 構造を使用して、いずれかの列を選択します。

SELECT 
    player_id,
    player_nickname,
    team_id,
    team_name,
    history_join_date,
    history_end_date,
    IF(history_end_date>history_join_date,history_end_date,history_join_date) as order_date
FROM 
    players
    INNER JOIN history
        ON history.history_user_id = players.player_id
    INNER JOIN teams
        ON history.history_team_id = teams.team_id
ORDER BY 
    order_date DESC;

@Barmarの回答から構築すると、GREATEST()を使用して最大の引数を選択することもできます。( MAX()はグループ化関数です...実際に探しているものではありません)

于 2012-08-22T23:43:55.400 に答える
0

あなたが望むのは次のとおりだと思います:

ORDER BY MAX(history_join_date, history_end_date)
于 2012-08-23T03:12:34.297 に答える