fix(veri): KURUM_DUZELT arşiv tablosunu da tarar (BACKLOG #21)
Dün Aşama D yalnız `programs`'a uygulanmıştı; `programs_arsiv`'de aynı yanlış
etiket duruyordu (31 ULUSLARARASI BALKAN + 30 ULUSLARARASI SARAYBOSNA
`unitur='DEVLET'`, Balkan'ın 24 satırında il Saraybosna). Kapanan programlar
arşive `programs`'tan olduğu gibi taşındığı için etiket oraya da yazılmış.
- `unitur-onar.ts` Aşama D iki tabloyu da tarar (`programs_arsiv` varsa).
Dokunulan kolon yalnız `unitur` ve `il`; A/B/C aşamaları `programs`'ta kalır.
- `veri-kalite.ts` kontrol 13 ve 14 arşivi de tarar. Genişletme olmadan iki
tablo ayrışabilir ve denetim bunu görmez.
- Yanlış etiket duran DB'de iki kontrol de KALDI veriyor (çıkış kodu 1):
`baz ad başına tek unitur — … BALKAN/YURTDISI KAMU,DEVLET/81 ; … SARAYBOSNA/68`
`DEVLET etiketi Türkiye ili ile destekli — … /SARAYBOSNA - BOSNA - HERSEK/31 ; /30`
Kullanıcıya bugün yansımıyor: `src/` tarafında `programs_arsiv`'i okuyan SQL
yok. Düzeltme tablo ileride okunduğunda sızıntının geri gelmemesi içindir.
Dünkü veri commit'inin (1df86cf) gövdesindeki rakam düzeltmesi: "/universiteler
hub'ında Devlet listesi 170 → 166" YANLIŞTIR. 170/166 ham `programs.universite`
ad sayısıdır, hub satırı değil; `uniAdiNormalize` parantezli eki attığı için
Kıbrıs Amerikan'ın iki yazımı tek slug. Hub'daki doğru değişim 132 → 129 kurum
(3 kurum). Kaynak: `12-kod-denetimi.md` O1, dalın kendi build HTML'i.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,8 @@
|
|||||||
* satır unitur=NULL kalıyor ve bunlar hem devlet/vakıf filtrelerinden hem
|
* satır unitur=NULL kalıyor ve bunlar hem devlet/vakıf filtrelerinden hem
|
||||||
* sihirbaz sayaçlarından sessizce düşüyor. Onarım dört aşamalı:
|
* sihirbaz sayaçlarından sessizce düşüyor. Onarım dört aşamalı:
|
||||||
*
|
*
|
||||||
* D) Kaynak veride DOLU ama YANLIŞ olan kurum alanları (KURUM_DUZELT)
|
* D) Kaynak veride DOLU ama YANLIŞ olan kurum alanları (KURUM_DUZELT) —
|
||||||
|
* `programs` VE `programs_arsiv` üzerinde
|
||||||
* A) Aynı üniversitenin dolu satırından kopyala (Nişantaşı, Beykent…)
|
* A) Aynı üniversitenin dolu satırından kopyala (Nişantaşı, Beykent…)
|
||||||
* B) Kalanlarda il KKTC yerleşimiyse unitur='KKTC'
|
* B) Kalanlarda il KKTC yerleşimiyse unitur='KKTC'
|
||||||
* C) Küçük manuel eşleme (Cerrahpaşa, MSB/İçişleri, Alanya, Manas…)
|
* C) Küçük manuel eşleme (Cerrahpaşa, MSB/İçişleri, Alanya, Manas…)
|
||||||
@@ -14,14 +15,16 @@
|
|||||||
* duplikat adlar normalize edilir; refresh.ts insert yolunda da aynı
|
* duplikat adlar normalize edilir; refresh.ts insert yolunda da aynı
|
||||||
* normalizasyon uygulanır ki duplikat bir daha oluşmasın.
|
* normalizasyon uygulanır ki duplikat bir daha oluşmasın.
|
||||||
*
|
*
|
||||||
* İdempotenttir. A/B/C yalnızca NULL satırlara dokunur; D (KURUM_DUZELT)
|
* İdempotenttir. A/B/C yalnızca `programs` tablosunun NULL satırlarına dokunur;
|
||||||
* NULL koşulundan bağımsızdır — düzelttiği alanlar dolu ama yanlış.
|
* D (KURUM_DUZELT) NULL koşulundan bağımsızdır — düzelttiği alanlar dolu ama
|
||||||
|
* yanlış — ve `programs_arsiv`'i de tarar (varsa).
|
||||||
*
|
*
|
||||||
* Kullanım: npx tsx scripts/unitur-onar.ts (dev sunucu KAPALIYKEN —
|
* Kullanım: npx tsx scripts/unitur-onar.ts (dev sunucu KAPALIYKEN —
|
||||||
* uygulama DB'yi readonly açar ama WAL checkpoint için tek yazar olmalı)
|
* uygulama DB'yi readonly açar ama WAL checkpoint için tek yazar olmalı)
|
||||||
*/
|
*/
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import Database from "better-sqlite3";
|
import Database from "better-sqlite3";
|
||||||
|
import { tabloVar } from "./yokatlas-goc";
|
||||||
|
|
||||||
/** Tire etrafı boşluk + çift boşluk temizliği (üniversite adı için). */
|
/** Tire etrafı boşluk + çift boşluk temizliği (üniversite adı için). */
|
||||||
export function uniAdiNormalize(ad: string): string {
|
export function uniAdiNormalize(ad: string): string {
|
||||||
@@ -75,6 +78,11 @@ const MANUEL_IL: Record<string, string> = {
|
|||||||
*
|
*
|
||||||
* `il` düzeltmesi yalnız YANLIŞ yazılmış değeri hedefler (yanlis → dogru);
|
* `il` düzeltmesi yalnız YANLIŞ yazılmış değeri hedefler (yanlis → dogru);
|
||||||
* boş il'ler kapsam dışı — eksik, eksik olarak görünmeli.
|
* boş il'ler kapsam dışı — eksik, eksik olarak görünmeli.
|
||||||
|
*
|
||||||
|
* Aynı yanlış etiket `programs_arsiv`'e de yazılmıştı (kapanan programlar oraya
|
||||||
|
* `programs`'tan olduğu gibi taşınıyor). Bugün `src/` tarafında arşivi okuyan
|
||||||
|
* SQL yok, ama tablo ileride okunursa sızıntı geri gelirdi; bu yüzden Aşama D
|
||||||
|
* iki tabloyu da tarar. Dokunulan kolon yalnız `unitur` ve `il`.
|
||||||
*/
|
*/
|
||||||
const KURUM_DUZELT: Record<
|
const KURUM_DUZELT: Record<
|
||||||
string,
|
string,
|
||||||
@@ -112,11 +120,17 @@ export function uniturOnar(db: Database.Database): void {
|
|||||||
|
|
||||||
// D) Dolu ama yanlış kurum alanları. A'dan ÖNCE koşar: yanlış değer başka
|
// D) Dolu ama yanlış kurum alanları. A'dan ÖNCE koşar: yanlış değer başka
|
||||||
// satırlara kopyalanmadan düzelsin. NULL koşulu yok; değer zaten dolu.
|
// satırlara kopyalanmadan düzelsin. NULL koşulu yok; değer zaten dolu.
|
||||||
|
// `programs` ve (varsa) `programs_arsiv` aynı haritadan geçer — iki tablo
|
||||||
|
// ayrışırsa arşiv ileride okunduğunda aynı sızıntı geri gelir.
|
||||||
|
const dTablolar = tabloVar(db, "programs_arsiv")
|
||||||
|
? ["programs", "programs_arsiv"]
|
||||||
|
: ["programs"];
|
||||||
|
for (const tablo of dTablolar) {
|
||||||
const dUnitur = db.prepare(
|
const dUnitur = db.prepare(
|
||||||
"UPDATE programs SET unitur = ? WHERE universite = ? AND unitur IS NOT ?"
|
`UPDATE ${tablo} SET unitur = ? WHERE universite = ? AND unitur IS NOT ?`
|
||||||
);
|
);
|
||||||
const dIl = db.prepare(
|
const dIl = db.prepare(
|
||||||
"UPDATE programs SET il = ? WHERE universite = ? AND il = ?"
|
`UPDATE ${tablo} SET il = ? WHERE universite = ? AND il = ?`
|
||||||
);
|
);
|
||||||
let dUniturToplam = 0;
|
let dUniturToplam = 0;
|
||||||
let dIlToplam = 0;
|
let dIlToplam = 0;
|
||||||
@@ -129,8 +143,9 @@ export function uniturOnar(db: Database.Database): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(
|
console.log(
|
||||||
`Aşama D (yanlış kurum alanı): unitur ${dUniturToplam} satır, il ${dIlToplam} satır`
|
`Aşama D (yanlış kurum alanı) ${tablo}: unitur ${dUniturToplam} satır, il ${dIlToplam} satır`
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// A) Aynı üniversitenin dolu satırından kopyala. Birden fazla FARKLI dolu
|
// A) Aynı üniversitenin dolu satırından kopyala. Birden fazla FARKLI dolu
|
||||||
// değer varsa sessizce seçim yapma — kaynak veride tutarsızlık demektir.
|
// değer varsa sessizce seçim yapma — kaynak veride tutarsızlık demektir.
|
||||||
@@ -211,11 +226,18 @@ if (process.argv[1]?.endsWith("unitur-onar.ts")) {
|
|||||||
db.pragma("journal_mode = WAL");
|
db.pragma("journal_mode = WAL");
|
||||||
db.transaction(() => uniturOnar(db))();
|
db.transaction(() => uniturOnar(db))();
|
||||||
db.pragma("wal_checkpoint(TRUNCATE)");
|
db.pragma("wal_checkpoint(TRUNCATE)");
|
||||||
|
for (const tablo of tabloVar(db, "programs_arsiv")
|
||||||
|
? ["programs", "programs_arsiv"]
|
||||||
|
: ["programs"]) {
|
||||||
const dagilim = db
|
const dagilim = db
|
||||||
.prepare(
|
.prepare(
|
||||||
"SELECT COALESCE(unitur,'(NULL)') AS t, COUNT(*) AS n FROM programs GROUP BY unitur ORDER BY n DESC"
|
`SELECT COALESCE(unitur,'(NULL)') AS t, COUNT(*) AS n FROM ${tablo} GROUP BY unitur ORDER BY n DESC`
|
||||||
)
|
)
|
||||||
.all() as { t: string; n: number }[];
|
.all() as { t: string; n: number }[];
|
||||||
console.log("Dağılım:", dagilim.map((d) => `${d.t}=${d.n}`).join(" "));
|
console.log(
|
||||||
|
`Dağılım (${tablo}):`,
|
||||||
|
dagilim.map((d) => `${d.t}=${d.n}`).join(" ")
|
||||||
|
);
|
||||||
|
}
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -299,9 +299,17 @@ async function main() {
|
|||||||
// görünmüyordu. Baz ad = sondaki parantezli ek atılmış hâl.
|
// görünmüyordu. Baz ad = sondaki parantezli ek atılmış hâl.
|
||||||
const BAZ_AD =
|
const BAZ_AD =
|
||||||
"TRIM(CASE WHEN instr(universite, '(') > 0 THEN substr(universite, 1, instr(universite, '(') - 1) ELSE universite END)";
|
"TRIM(CASE WHEN instr(universite, '(') > 0 THEN substr(universite, 1, instr(universite, '(') - 1) ELSE universite END)";
|
||||||
|
// 13 ve 14 arşivi de tarar: kapanan programlar `programs_arsiv`'e olduğu gibi
|
||||||
|
// taşındığı için yanlış etiket orada da duruyordu (BACKLOG #21). Bugün `src/`
|
||||||
|
// tarafında arşivi okuyan SQL yok, ama iki tablo ayrışırsa denetim bunu
|
||||||
|
// görmez ve tablo ileride okunduğunda sızıntı geri gelir.
|
||||||
|
const KURUMLAR = tabloVar(db, "programs_arsiv")
|
||||||
|
? `(SELECT universite, unitur, il FROM programs
|
||||||
|
UNION ALL SELECT universite, unitur, il FROM programs_arsiv)`
|
||||||
|
: "programs";
|
||||||
const bazAdCeliskileri = `(SELECT ${BAZ_AD} AS bazAd, GROUP_CONCAT(DISTINCT unitur) AS turler, COUNT(*) AS adet,
|
const bazAdCeliskileri = `(SELECT ${BAZ_AD} AS bazAd, GROUP_CONCAT(DISTINCT unitur) AS turler, COUNT(*) AS adet,
|
||||||
MAX(unitur = 'DEVLET') <> MIN(unitur = 'DEVLET') AS devletBolunmus
|
MAX(unitur = 'DEVLET') <> MIN(unitur = 'DEVLET') AS devletBolunmus
|
||||||
FROM programs WHERE unitur IS NOT NULL GROUP BY 1 HAVING COUNT(DISTINCT unitur) > 1)`;
|
FROM ${KURUMLAR} WHERE unitur IS NOT NULL GROUP BY 1 HAVING COUNT(DISTINCT unitur) > 1)`;
|
||||||
const bolunmus = ornek(`SELECT bazAd, turler, adet FROM ${bazAdCeliskileri} WHERE devletBolunmus`);
|
const bolunmus = ornek(`SELECT bazAd, turler, adet FROM ${bazAdCeliskileri} WHERE devletBolunmus`);
|
||||||
zorunlu(
|
zorunlu(
|
||||||
"baz ad başına tek unitur",
|
"baz ad başına tek unitur",
|
||||||
@@ -318,7 +326,7 @@ async function main() {
|
|||||||
// Türkiye illerinde tire geçmez; yurt dışı iller tireli (BİŞKEK-KIRGIZİSTAN…),
|
// Türkiye illerinde tire geçmez; yurt dışı iller tireli (BİŞKEK-KIRGIZİSTAN…),
|
||||||
// KKTC illeri KKTC_ILLERI'nde. İli hiç olmayan kurumlar (MSB/İçişleri) hariç.
|
// KKTC illeri KKTC_ILLERI'nde. İli hiç olmayan kurumlar (MSB/İçişleri) hariç.
|
||||||
const yurtDisiDevlet = ornek(
|
const yurtDisiDevlet = ornek(
|
||||||
`SELECT universite, GROUP_CONCAT(DISTINCT il), COUNT(*) FROM programs
|
`SELECT universite, GROUP_CONCAT(DISTINCT il), COUNT(*) FROM ${KURUMLAR}
|
||||||
WHERE unitur = 'DEVLET' GROUP BY universite
|
WHERE unitur = 'DEVLET' GROUP BY universite
|
||||||
HAVING SUM(il IS NOT NULL) > 0
|
HAVING SUM(il IS NOT NULL) > 0
|
||||||
AND SUM(il NOT LIKE '%-%' AND il NOT IN (${KKTC_ILLERI.map(() => "?").join(",")})) = 0`,
|
AND SUM(il NOT LIKE '%-%' AND il NOT IN (${KKTC_ILLERI.map(() => "?").join(",")})) = 0`,
|
||||||
|
|||||||
Reference in New Issue
Block a user