【问题标题】:Join 2 tables and display duplicated row value into new column加入 2 个表并将重复的行值显示到新列中
【发布时间】:2021-09-07 00:41:40
【问题描述】:

我已经花了 2 天的时间来解决这个问题,但找不到任何帮助。

我有 2 张桌子。

1.玩家

id name
1 AA
2 BB
3 CC
4 DD

2。匹配

id player_id match_id date has_opponent
1 1 1 2021-06-23 0
2 2 1 2021-06-23 0
3 3 2 2021-06-21 0
4 4 3 2021-06-22 1

预期结果

match_id date first_opponent_name second_opponent_name
1 2021-06-23 AA BB
2 2021-06-21 CC
3 2021-06-22 DD DD

我想用新列加入这两个表( first_opponent_name 和 second_opponent_name ) 如果满足以下条件:

  1. 如果有一个重复的 ma​​tch_id 但它有不同的 player_id,则在 2 个单独的列中显示他们的名字。
  2. 如果只有 1 个 ma​​tch_id 并且它有 1 个 player_id 并且 has_opponent 列为 0,那么这应该只显示 first_opponent_name
  3. 如果只有 1 个 ma​​tch_id 并且它有 1 个 player_id 并且 has_opponent 列为 1,那么 first_opponent_namesecond_opponent strong> _name 应该显示为相同的值。

【问题讨论】:

  • 到目前为止您尝试了哪些方法,您在哪里卡住了?
  • 那些针对性的问题,听起来像是功课?
  • 我正在尝试创建一个预订系统,先生!

标签: mysql sql


【解决方案1】:

未经测试,但我认为这会起作用,基本上它在不同的场景中将表连接到自身,然后检查它匹配的场景。

SELECT
  m.match_id
 ,m.date
 ,p1.name AS first_opponent_name
 ,CASE WHEN p2.name IS NOT NULL THEN p2.name 
       WHEN nop2.match_id IS NOT NULL THEN '' 
       WHEN samep2.match_id IS NOT NULL THEN p1.name END AS second_opponent_name 
FROM
  matching AS m
INNER JOIN players AS p1
  ON m.player_id = p1.player_id 
LEFT JOIN matching AS hasp2
  ON m.match_id = hasp2.match_id
  AND m.player_id <> hasp2.player_id
LEFT JOIN players AS p2
  ON hasp2.player_id = p2.player_id
LEFT JOIN (
  SELECT
    match_id
  FROM
    matching
  WHERE
    has_opponent = 0
  GROUP BY
    match_id
  HAVING COUNT(*) = 1
) AS nop2
  ON m.match_id = nop2.match_id
LEFT JOIN (
  SELECT
    match_id
  FROM
    matching
  WHERE
    has_opponent = 1
) AS samep2
  ON m.match_id = samep2.match_id

可以说,您可以放弃 hasp2 或 samep2 连接,并假设如果不满足其他两种情况,则取决于您对数据的信任程度,以了解这是否是一个可行的选择。

【讨论】:

  • 非常感谢您提供的解决方案,特别是提到数据的可信度。
【解决方案2】:
WITH cte AS ( SELECT DISTINCT
                     match_id,
                     `date`,
                     MIN(player_id) OVER (PARTITION BY match_id) p1,
                     MAX(player_id) OVER (PARTITION BY match_id) p2,
                     has_opponent
              FROM matching )
SELECT match_id,
       `date`,
       p1.name first_opponent_name,
       CASE WHEN has_opponent OR (p1 != p2) THEN p2.name END second_opponent_name
FROM cte
JOIN players p1 ON cte.p1 = p1.id
JOIN players p2 ON cte.p2 = p2.id
ORDER BY 1

如果不支持 CTE 和窗口函数,则

SELECT match_id,
       `date`,
       p1.name first_opponent_name,
       CASE WHEN has_opponent OR (p1 != p2) THEN p2.name END second_opponent_name
FROM ( SELECT match_id,
              `date`,
              MIN(player_id) p1,
              MAX(player_id) p2,
              has_opponent
       FROM matching
       GROUP BY match_id,
                `date`,
                has_opponent ) cte
JOIN players p1 ON cte.p1 = p1.id
JOIN players p2 ON cte.p2 = p2.id
ORDER BY 1

https://dbfiddle.uk/?rdbms=mysql_8.0&rdbms2=mysql_5.7&fiddle=4b947a2e7d31d50dfc1242b194b204fe

查询假定相同的match_id 严格匹配相同的datematch_id

【讨论】:

  • 真的很感激,兄弟!
【解决方案3】:

唯一棘手的部分是处理多个玩家,这非常适合使用窗口函数和row_number();那么这只是将这些与条件案例聚合起来的案例:

select match_Id, date, 
    Max(case when cnt=1
        then name 
    else
        case when rn=1 then name end
    end) first_opponent_name,

    Max(case when cnt=1 then
        case when has_opponent=1 then name else '' end
    else
        case when rn=2 then name end
    end) second_opponent_name

from (
    select m.match_id, m.date, m.has_opponent, p.name, 
      Row_Number() over(partition by match_id order by player_id)rn, 
      Count(*) over (partition by match_id) cnt
    from matching m
    join players p on p.id=m.player_id
)x
group by match_id, date

working example Fiddle

【讨论】:

  • 不错的解决方案,值得注意的是窗口函数仅在 MySQL 8+ 和 MariaDB 10.2+ 中使用
  • 第一次知道有这样的功能。谢谢!
  • 我只是想知道为什么我们必须在这里使用聚合函数 MAX() ?因为它只会返回一个值。
  • @samrith.v 因为查询正在聚合行 - 如果有多个玩家,则返回 2 行需要使用 group by 折叠成 1 行 - case 表达式返回我们的值want 或 nullmax 将这些聚合为 1 行,丢弃 null
  • 非常感谢您的解释。
猜你喜欢
  • 1970-01-01
  • 2011-10-15
  • 2019-10-06
  • 1970-01-01
  • 2023-03-17
  • 2018-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多