You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL实现同名不同格式球员数据分组求和及Knex.js方案

Hey there! Let's fix this name normalization issue so you can properly group those player stats. The key here is to standardize all those messy name variations into a consistent format before grouping—PostgreSQL won't automatically recognize "Kane, Patrick" and "P.Kane, Patrick*" as the same player, so we need to clean them up first.

First, let's cover the Knex.js approach since that's your priority, then follow up with raw PostgreSQL SQL for reference.

Knex.js Solution

We'll use PostgreSQL's regex functions within Knex raw queries to normalize the player names, then group by the cleaned-up name:

// Define the name normalization logic as a Knex raw expression
const normalizedPlayerName = knex.raw(`
  TRIM(
    REGEXP_REPLACE(
      // Remove leading initials (like "P." at the start of the name)
      REGEXP_REPLACE(player_name, '^[A-Za-z]\\.', '', 'g'),
      // Remove trailing special characters (like "*" at the end)
      '[^A-Za-z\\s,]$', '', 'g'
    )
  ) AS normalized_player_name
`);

// Build the aggregation query
const aggregatedStats = await knex('player_stats')
  .select(
    knex.raw('SUM(games_played) AS games_played'),
    knex.raw('SUM(goals) AS goals'),
    knex.raw('SUM(points) AS points'),
    normalizedPlayerName
  )
  .groupBy('normalized_player_name');

Raw PostgreSQL SQL Solution

If you prefer writing raw SQL directly (maybe for testing or more complex adjustments), here's the equivalent query:

SELECT
  SUM(games_played) AS games_played,
  SUM(goals) AS goals,
  SUM(points) AS points,
  TRIM(
    REGEXP_REPLACE(
      REGEXP_REPLACE(player_name, '^[A-Za-z]\.', '', 'g'),
      '[^A-Za-z\s,]$', '', 'g'
    )
  ) AS normalized_player_name
FROM player_stats
GROUP BY normalized_player_name;

Testing & Adjusting the Normalization Logic

Before running the full aggregation, I recommend testing the name cleaning to make sure it handles all your variations correctly. For example:

Knex Test Query

const testNameCleanup = await knex('player_stats')
  .select(
    'player_name',
    knex.raw(`
      TRIM(
        REGEXP_REPLACE(
          REGEXP_REPLACE(player_name, '^[A-Za-z]\\.', '', 'g'),
          '[^A-Za-z\\s,]$', '', 'g'
        )
      ) AS normalized_name
    `)
  )
  .where('player_name', 'LIKE', '%Kane%') // Test with a specific player's variations
  .limit(10);

Raw SQL Test Query

SELECT
  player_name,
  TRIM(
    REGEXP_REPLACE(
      REGEXP_REPLACE(player_name, '^[A-Za-z]\.', '', 'g'),
      '[^A-Za-z\s,]$', '', 'g'
    )
  ) AS normalized_name
FROM player_stats
WHERE player_name LIKE '%Kane%'
LIMIT 10;

Notes for Edge Cases

  • If you have other variations (like names with middle initials in the middle, or parentheses like "Kane, Patrick (II)"), you can extend the regex. For example, add another REGEXP_REPLACE to remove parenthetical content: REGEXP_REPLACE(..., '\(.*\)', '', 'g')
  • If case differences matter (e.g., "kane, patrick" vs "Kane, Patrick"), wrap the normalized name in LOWER() to group case-insensitively: LOWER(TRIM(...)) AS normalized_player_name

内容的提问来源于stack exchange,提问作者jkwok97

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:35:34