简体   繁体   English

如何订购此特定的内部联接?

[英]How to order this specific Inner Joins?

Right now I'm creating an online game where I list the last transfers of players. 现在,我正在创建一个在线游戏,其中列出了玩家的最后转会。

The table that handles the history of players, has the columns history_join_date and history_end_date. 处理玩家历史记录的表具有“ history_join_date”和“ history_end_date”列。

When history_end_date is filled, it means that player left a club, and when it is like the default (0000-00-00 00:00:00) and history_join_date has some date it means player joined the club (in that date). 当history_end_date填满时,表示玩家离开了俱乐部,当它像默认值(0000-00-00 00:00:00)且history_join_date具有某个日期时,表示玩家已加入俱乐部(在该日期)。

Right now, I've the following query: 现在,我有以下查询:

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

However, this query returns something like (filtered with PHP above): 但是,此查询返回的内容类似于(上面用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 Filter: 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']));
}

As you can see, in the transfers order, the date is not being followed strictly (22-Aug => 21-Aug => 22-Aug). 如您所见,在转移顺序中,日期未严格遵循(22-Aug => 21-Aug => 22-Aug)。

What am I missing in the SQL? 我在SQL中缺少什么?

Regards! 问候!

The issue is you are ordering based upon two different values. 问题是您要根据两个不同的值订购。 So your results are ordered first by history_end_date, and when the end dates are equal (ie when it is the default value), they are then ordered by history_join_date 因此,您的结果首先按history_end_date排序,并且当结束日期相等时(即,当它是默认值时),然后按history_join_date对其进行排序。

(Note that your first results are all ends, and then your subsequent results are all joins, and each subset is properly ordered). (请注意,您的第一个结果是所有结尾,然后您的后续结果是所有联接,并且每个子集的顺序都正确)。

How much control do you have over this data structure? 您对该数据结构有多少控制权? You might be able to restructure the history table such that there is only a single date, and a history type of JOINED or END... You might be able to make a view of joined_date and end_date and sort across that... 您可能能够重组历史记录表,以便只有一个日期,并且历史记录类型为JOINED或END...。您可能能够查看join_date和end_date并对其进行排序...


From what you have in the question I made up the following DDL & Data: 根据您的问题,我组成了以下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);

SOLUTION ONE - History Event View 解决方案一-历史事件视图

This is obviously not the only solution (and you'd have to evaluate options as they suit your needs, but you could create a view in MySQL for your history events and join to it and use it for ordering similar to the following: 显然,这不是唯一的解决方案(并且您必须评估满足其需求的选项,但是您可以在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";

Your select then becomes: 您的选择将变为:

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;

Benefit here is you can get both joins and leaves for the same player. 这样做的好处是您可以为同一位玩家获得加入和离开的机会。


SOLUTION TWO - Pseudo column. 解决方案二-伪列。 use the IF construction to pick one or the other column. 使用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;

Building from @Barmar's answer, you can also use GREATEST() to pick the greatest of the arguments. 从@Barmar的答案开始,您还可以使用GREATEST()选择最大的参数。 ( MAX() is a grouping function... not actually what you're looking for) MAX()是一个分组函数...实际上不是您想要的东西)

我认为您想要的是:

ORDER BY MAX(history_join_date, history_end_date)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM