Sichern Sie sich heute 20%. Verwenden Sie beim Bezahlvorgang den Code WELCOME. WILLKOMMEN

SQL & Identifiers Migration: steam/license → citize&#…

Anwendungsfall: Anwendungsfall: Sie wechseln von ESX zu QBCore oder QBOX (qbx_core) und benötigen eine saubere, prüffähige Migration von Spielerkennungen und -salden. Dieser Leitfaden bietet Ihnen produktionsbereites SQL, einen reversiblen Plan und Validierungsschritte.

Verwandte Artikel:


Was ändert sich zwischen ESX und QBCore/QBOX

ThemaESX (allgemein)QBCore / QBOX (allgemein)
Primärer SpielerschlüsselKennung (z.B, Lizenz:xxx oder Vermächtnis Dampf:xxx)Bürger-ID (servergeneriertes Token)
Alt-KennungenBenutzerkennung, manchmal eine separate Kennungen TischSpalten wie Lizenz, Dampf, fivem nebenbei gespeichert Bürger-ID
GeldmodellGetrennte Konten (Bargeld/Bank/Schwarzgeld) über Benutzerkonten (JSON) oder Benutzerkonten ReihenEinzel Geld JSON auf Spieler (z.B, { "Bargeld": 0, "Bank": 5000 }); optionale zusätzliche Geldbörsen
Fahrzeugeowned_vehicles.owner bezieht sich auf ESX KennungSpielerfahrzeuge.Bürger-ID (oder Lizenz auf einigen Gabeln)

QBOX folgt im Allgemeinen der DB-Form von QB. Behandeln Sie QBOX als „QB-Schema + qbx-Ergänzungen“. Vergleichen Sie immer Ihr Live-Schema.


Goldene Regeln (nicht überspringen)

  1. Schreibvorgänge einfrieren während der Migration (stoppen Sie den Spielserver und alle externen Bots, die die Datenbank berühren).
  2. Vollständige Sicherung und ein Dump von Tabellenstrukturen. Speichern Sie beide mit Zeitstempeln.
  3. Arbeiten in einer Transaktion wenn möglich pro Tabelle; halten Sie die Schritte idempotent.
  4. Erstellen Sie einen Zebrastreifen (alte_KennungBürger-ID), die Sie wiederverwenden oder wiederherstellen können.

Ziel, das Sie anstreben (QB/QBOX-Basislinie)

Ein typisches Spieler Tabelle (Spalten variieren je nach Gabel):

-- Überprüfen Sie Ihr aktuelles Schema und passen Sie es an. BESCHREIBEN Sie die Spieler; -- Erwarten Sie Spalten wie: Bürger-ID, Lizenz, Name, Geld, Charinfo, Job, Gang, Metadaten
  • Bürger-ID: Primärschlüssel, der in QB/QBOX verwendet wird.
  • Lizenz/Steam: Für forensische Zwecke und zum erneuten Verknüpfen aufbewahren.
  • Geld (JSON): zB {"Bargeld":123,"Bank":456}. Einige Server fügen hinzu Krypto, schmutzig, usw.

Schritt 0 – Snapshot und Staging

# MySQL/MariaDB backup
mysqldump -u root -p --routines --triggers yourdb > yourdb_$(date +%F_%H%M).sql

# Optional: structure‑only snapshot
mysqldump -u root -p --no-data yourdb > yourdb_schema_$(date +%F_%H%M).sql

Starten Sie eine Staging-Kopie. Führen Sie dort zuerst alles aus

Schritt 1 – Erstellen Sie die Zebrastreifen Tisch

Wir mappen jeden ESX Kennung zu einem neuen Bürger-ID. Wenn Sie bereits eine Spieler Tabelle mit Bürger-IDs, kehren Sie die Zuordnung um (siehe Vorhandene QB-Spieler Hinweis unten).

-- 1) Crosswalk erstellen. CREATE TABLE IF NOT EXISTS identifier_crosswalk (old_identifier VARCHAR(60) PRIMARY KEY, citizenid VARCHAR(20) NOT NULL, license VARCHAR(60) NULL, steam VARCHAR(60) NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 2) Seed von ESX-Benutzern (passen Sie die Tabellen-/Spaltennamen an Ihre ESX-Variante an) -- Im allgemeinen ESX enthält „users.identifier“ die Lizenz:xxx oder Steam:xxx. INSERT IGNORE INTO identifier_crosswalk (old_identifier, license, steam, citizenid) SELECT u.identifier AS old_identifier, CASE WHEN u.identifier LIKE 'license:%' THEN u.identifier ELSE NULL END AS license, CASE WHEN u.identifier LIKE 'steam:%' THEN u.identifier ELSE NULL END AS steam, UPPER(SUBSTRING(REPLACE(UUID(),'-',''),1,10)) AS citizenid FROM users u; -- 3) Wenn Sie eine separate Tabelle „Kennungen“ haben, führen Sie die bekanntesten Werte zusammen -- Beispiel (optional): Lizenz bevorzugen, wenn verfügbar UPDATE identifier_crosswalk x JOIN ( SELECT i1.identifier AS old_identifier, MAX(CASE WHEN i1.type='license' THEN i1.value END) AS license, MAX(CASE WHEN i1.type='steam' THEN i1.value END) AS steam FROM identifiers i1 GROUP BY i1.identifier ) i ON i.old_identifier = x.old_identifier SET x.license = COALESCE(i.license, x.license), x.steam = COALESCE(i.steam, x.steam); -- 4) Eindeutigkeit und Indizes ALTER TABLE identifier_crosswalk ADD UNIQUE KEY ux_cid (citizenid), ADD KEY ix_license (license), ADD KEY ix_steam (steam);

Vorhandene QB-Spieler? Wenn Sie bereits Spieler Zeilen, erstellen Sie den Zebrastreifen, indem Sie ihre Lizenz/Dampf Und bestehende Bürger-ID anstatt neue zu generieren. Ihr Crosswalk darf einem vorhandenen QB-Spieler niemals eine neue Citizen-ID zuweisen.


Schritt 2 – Ziel normalisieren/vorbereiten Spieler Reihen

Erstellen Sie ggf. fehlende Spieler Zeilen basierend auf ESX Benutzer.

-- Stellen Sie sicher, dass „players“ vorhanden ist, und überprüfen Sie zuerst seine Spalten. -- Wir fügen Shells nur für fehlende Bürger ein. INSERT INTO players (citizenid, license, name, money, charinfo, metadata) SELECT x.citizenid, COALESCE(NULLIF(x.license,''), NULLIF(x.steam,'')) AS license_like, COALESCE(u.firstname, '') || ' ' || COALESCE(u.lastname, '') AS name_like, '{"bargeld":0,"bank":0}' AS Geld, JSON_OBJECT( 'Vorname', COALESCE(u.firstname,''), 'Nachname', COALESCE(u.lastname,''), 'Geburtsdatum', COALESCE(u.dateofbirth,''), 'Geschlecht', COALESCE(u.sex,'') ) AS charinfo, JSON_OBJECT('esx_identifier', u.identifier) AS Metadaten VON Benutzern u JOIN identifier_crosswalk x ON x.old_identifier = u.identifier LEFT JOIN Spieler p ON p.citizenid = x.citizenid WHERE p.citizenid IS NULL;

Notiz: Verwenden Sie die Zeichenfolgenverkettung Ihrer SQL-Variante (CONCAT in MySQL) und JSON-Funktionen entsprechend. Für MySQL 5.7 ersetzen JSON_OBJECT mit manuellem Saitenaufbau, falls erforderlich.

MySQL‑sichere Variante:

INSERT INTO players (citizenid, license, name, money, charinfo, metadata) SELECT x.citizenid, COALESCE(NULLIF(x.license,''), NULLIF(x.steam,'')) AS license_like, TRIM(CONCAT(COALESCE(u.firstname,''), ' ', COALESCE(u.lastname,''))) AS name_like, '{"cash":0,"bank":0}' AS money, CONCAT('{', '"firstName":"', REPLACE(COALESCE(u.firstname,''),'"','\"'), '",', '"lastName":"', REPLACE(COALESCE(u.lastname,''),'"','\"'), '",', '"birthdate":"', REPLACE(COALESCE(u.dateofbirth,''),'"','\"'),'",', „Geschlecht“: „“, ERSETZEN (COALESCE (u.Geschlecht, „), „“, „\“ „), „“ „, „}“) ALS Charinfo, CONCAT („{“, „esx_identifier“: „“, ERSETZEN (u.identifier, „“, „\“ „), „“ „, „}“) ALS Metadaten VON Benutzern u JOIN identifier_crosswalk x ON x.old_identifier = u.identifier LEFT JOIN Spieler p ON p.citizenid = x.citizenid WHERE p.citizenid IS NULL;

Schritt 3 – Migrieren Konten → Geld

Es gibt zwei gängige ESX-Muster:

A) ESX speichert Guthaben im Inneren Benutzerkonten JSON

-- Beispiel: users.accounts = '{"bank":5000, "money":750, "black_money":200}' -- 1) Sicheres Extrahieren aus ESX JSON -- Erstellen Sie eine temporäre Ansicht/Tabelle mit analysierten Zahlen CREATE TEMPORARY TABLE esx_balances AS SELECT u.identifier, COALESCE(JSON_EXTRACT(u.accounts, '$.money'), 0) AS esx_cash, COALESCE(JSON_EXTRACT(u.accounts, '$.bank'), 0) AS esx_bank, COALESCE(JSON_EXTRACT(u.accounts, '$.black_money'), 0) AS esx_black FROM users u; -- 2) Zusammenführen in QB/QBOX-Geld JSON -- Entscheiden Sie, wie mit Schwarzgeld verfahren werden soll (siehe Optionen unten) UPDATE players p JOIN identifier_crosswalk x ON x.citizenid = p.citizenid JOIN esx_balances b ON b.identifier = x.old_identifier SET p.money = JSON_OBJECT( 'cash', CAST(b.esx_cash AS UNSIGNED), 'bank', CAST(b.esx_bank AS UNSIGNED) );

Wenn MySQL ohne native JSON-Operationen (oder alte Version): Erstellen Sie JSON-Strings mit CONCAT.

B) ESX speichert Guthaben in Benutzerkonten Reihen

-- Beispiel: user_accounts(Kennung, Konto, Geld) ERSTELLEN SIE EINE VORÜBERGEHENDE TABELLE esx_balances ALS AUSWÄHLEN ua.Kennung, SUMME(FALL, WENN ua.account='Geld' DANN ua.Geld SONST 0 ENDE) ALS esx_cash, SUMME(FALL, WENN ua.account='Bank' DANN ua.Geld SONST 0 ENDE) ALS esx_bank, SUMME(FALL, WENN ua.account='Schwarzgeld' DANN ua.Geld SONST 0 ENDE) ALS esx_black VON user_accounts ua GRUPPE NACH ua.Kennung; UPDATE Spieler p JOIN identifier_crosswalk x ON x.citizenid = p.citizenid JOIN esx_balances b ON b.identifier = x.old_identifier SET p.money = JSON_OBJECT( 'cash', CAST(b.esx_cash AS UNSIGNED), 'bank', CAST(b.esx_bank AS UNSIGNED) );

Handhabung Schwarzgeld (Wählen Sie eine Option)

  • Option 1 (empfohlen): Erstellen Sie einen dedizierten Wallet-Schlüssel in QB Money JSON, zB "schmutzig".
  • Option 2: Konvertieren Sie stattdessen in Artikel (z. B. markierte Rechnungen) und schreiben Sie den Bestand gut (erfordert Artikelmigration; liegt hier außerhalb des Geltungsbereichs).
  • Option 3: Setzen Sie es auf Null (dringend abgeraten, es sei denn, Sie haben einen Wipe angekündigt).

Implementierung von Option 1:

-- Dirty Wallet in JSON hinzufügen (Server, die zusätzliche Wallets unterstützen) UPDATE players p JOIN identifier_crosswalk x ON x.citizenid = p.citizenid JOIN esx_balances b ON b.identifier = x.old_identifier SET p.money = JSON_MERGE_PATCH(p.money, JSON_OBJECT('dirty', CAST(b.esx_black AS UNSIGNED)));

Stellen Sie sicher, dass Ihr Framework/Ihre Ressourcen das zusätzliche Budget tatsächlich berücksichtigen. Andernfalls bevorzugen Sie Option 2.


Schritt 4 – Neuschlüsselung fremder Tabellen, die auf ESX verweisen Kennung

Typische zu reparierende Tabellen:

  • owned_vehicles.owner → Karte zu Bürger-ID (QB: Spielerfahrzeuge.Bürger-ID)
  • Alle benutzerdefinierten Tabellen, die Kennung Spalten (Häuser, Abrechnungen, Banden, Geschäfte)

Fahrzeuge (ESX → QB)

-- Wenn Sie ESX „owned_vehicles“ behalten, ändern Sie den Schlüssel owner → citizenid aus Gründen der Vorwärtskompatibilität. ALTER TABLE owned_vehicles ADD COLUMN citizenid VARCHAR(20) NULL; UPDATE owned_vehicles v JOIN identifier_crosswalk x ON x.old_identifier = v.owner SET v.citizenid = x.citizenid WHERE v.citizenid IS NULL; CREATE INDEX ix_ov_cid ON owned_vehicles (citizenid);

**Fahrzeuge in QB's **“ (minimale Felder; an Ihr Schema anpassen):

INSERT IGNORE INTO player_vehicles (citizenid, plate, vehicle, state, garage) SELECT x.citizenid, v.plate, v.vehicle, 0 AS state, 'A' AS garage FROM owned_vehicles v JOIN identifier_crosswalk x ON x.old_identifier = v.owner;

JSON-Feldnamen validieren (Fahrzeug gegen Mods/Requisiten) und Spaltenliste mit Ihrem tatsächlichen QB/QBOX-Schema.


Schritt 5 – Einschränkungen, Indizes und Integritätsprüfungen

-- Ensure primary/unique keys
ALTER TABLE players
  ADD UNIQUE KEY ux_players_citizenid (citizenid);

-- Optional: keep a quick lookup by license/steam
ALTER TABLE players
  ADD KEY ix_players_license (license);

-- Spot orphaned crosswalks (no players row)
SELECT x.*
FROM identifier_crosswalk x
LEFT JOIN players p ON p.citizenid = x.citizenid
WHERE p.citizenid IS NULL;

-- Spot players with zeroed wallets (sanity)
SELECT citizenid, money FROM players
WHERE JSON_EXTRACT(money, '$.cash') IS NULL OR JSON_EXTRACT(money, '$.bank') IS NULL;

-- Detect duplicates (same human with multiple identifiers)
SELECT old_identifier, COUNT(*)
FROM identifier_crosswalk
GROUP BY old_identifier
HAVING COUNT(*) > 1;

Schritt 6 – Validierungssuite

  1. Zeilenanzahl: COUNT(Benutzer)COUNT(Spieler) (innerhalb der erwarteten Deltas).
  2. Saldensummen: Summe des ESX-Bargelds/Bankguthabens ≈ Summe der QB-Wallets nach der Migration.
  3. Beispielaudit: Wählen Sie 10 Spieler nach Namen aus; überprüfen Sie Bürger-ID, Waagen, Fahrzeuge.
  4. Login-Test: Server in den Staging-Modus bringen; einige bekannte Spieler anmelden; Benutzeroberflächen überprüfen.

Beispiele für die Summenprüfung:

-- ESX-Summen SELECT SUM(COALESCE(JSON_EXTRACT(Konten,'$.Geld'),0)) AS esx_cash_total, SUM(COALESCE(JSON_EXTRACT(Konten,'$.Bank'),0)) AS esx_bank_total FROM Benutzer; -- QB-Summen SELECT SUM(COALESCE(JSON_EXTRACT(Geld,'$.Geld'),0)) AS qb_cash_total, SUM(COALESCE(JSON_EXTRACT(Geld,'$.Bank'),0)) AS qb_bank_total FROM Spieler;

Schritt 7 – Laufzeitkompatibilität (Adapter)

Auch nach der Migration können einige ältere Skripte noch auf ESX verweisen Kennung. Behalten Sie die Zebrastreifen und verwenden Sie einen Helfer, um „ (oder umgekehrt) zur Laufzeit aufzulösen.

Lua-Helfer (Server):

--- lookup_citizenid.lua lokale Funktion getCitizenIdByIdentifier(Kennung) lokales Ergebnis = MySQL.query.await('SELECT citizenid FROM identifier_crosswalk WHERE old_identifier = ? LIMIT 1', {Kennung}) wenn Ergebnis und Ergebnis[1], dann gib Ergebnis[1].citizenid zurück, Ende, nil zurückgeben, Ende, { getCitizenIdByIdentifier = getCitizenIdByIdentifier}

Verwenden Sie dies in älteren Ereignishandlern, bis alle Skripte QB/QBOX-nativ sind. Vollständige Schnittstellen-Shims finden Sie im Artikel zu Adaptermustern.


Rollback-Strategie

  1. Halten Kennung_Fußgängerübergang und ein Sicherung vor der Migration.
  2. Wenn etwas schief geht, lassen Sie das neue Spieler in diesem Fenster erstellte Zeilen und stellen Sie die Sicherung wieder her.
  3. Führen Sie die Migration erneut aus, nachdem Sie die Datenrandfälle behoben haben.

Einfaches Etikett zum Markieren Ihres Fensters:

-- Neue Zeilen markieren UPDATE players SET metadata = JSON_MERGE_PATCH(COALESCE(metadata,'{}'), JSON_OBJECT('migration_tag','esx_to_qb_2025_08_16')) WHERE citizenid IN (SELECT citizenid FROM identifier_crosswalk);

Randfälle und Tipps

  • Mehrere Charaktere pro Mensch: Wenn Ihr ESX einen verwendet Kennung pro Konto (kein Multi-Char), aber Sie planen Multi-Char auf QB, ziehen Sie in Erwägung, später zusätzliche Bürger über In-Game-Flows zu generieren, nicht hier.
  • Namenskollisionen: Zwei ESX-Benutzer mit demselben Vor-/Nachnamen sind in Ordnung; Bürger-ID ist der Schlüssel.
  • Fehlen Werte: Bevorzugen Sie die stabile Kennung, die Sie haben (Dampf, Lizenz2, fivem). Auffüllen Spielerlizenz mit dem Besten, was es gibt.
  • Altes MySQL ohne JSON: Verwenden Sie JSON-Strings im Klartext und analysieren Sie sie im App-Code. Planen Sie ein Upgrade.
  • Schwarzgeldpolitik: Teilen Sie Ihre Entscheidung mit. Führen Sie bei der Konvertierung in Artikel eine separate, transparente Artikelmigration durch.

Checkliste für die Umstellung (Produktion)


Häufig gestellte Fragen

F: Kann ich ESX weiterhin verwenden? überall?
A: Ja, aber behandeln Sie es als Vermächtnis. Verwenden Sie den Crosswalk, um das Problem bei Bedarf zu lösen, und aktualisieren Sie die Skripte so schnell wie möglich auf CitizenID.

F: Benötigt QBOX ein anderes SQL?
A: Nicht für Kennungen/Geld; QBOX verfolgt das Schema von QB genau. Überprüfen Sie die Spaltennamen vor der Ausführung.

F: Was ist mit Lagerbeständen, Jobs, Gangs?
A: Nicht Gegenstand dieses Artikels. Behandeln Sie sie, nachdem sich Kennungen/Geld stabilisiert haben. Nutzen Sie den Pillar-Leitfaden für eine vollständige Abdeckung.


Nächste Schritte


Anhang – Idempotente Wrapper

Umschließen Sie kritische UPDATE/INSERTs mit Schutzvorrichtungen, damit Sie sie sicher erneut ausführen können.

-- Beispielwächter: Aktualisiere nur Spieler mit unberührtem Geld. UPDATE players p JOIN identifier_crosswalk x ON x.citizenid = p.citizenid JOIN esx_balances b ON b.identifier = x.old_identifier SET p.money = JSON_OBJECT('cash', CAST(b.esx_cash AS UNSIGNED), 'bank', CAST(b.esx_bank AS UNSIGNED)) WHERE JSON_EXTRACT(p.money, '$.cash') = 0 AND JSON_EXTRACT(p.money, '$.bank') = 0;

Behalten Sie den Zebrastreifen für immer. Er ist Ihr Rosettastein für alte Protokolle und Skripte.

Lukas
Lukas

Ich bin Luke, ein Gamer und schreibe gerne über FiveM, GTA und Rollenspiele. Ich betreibe eine Rollenspiel-Community und habe etwa 10 Jahre Erfahrung in der Verwaltung von Servern.

Artikel570