Я создал процедуру PHP, которая извлекает некоторые имена таблиц из базы данных, а затем сортирует их на основе собственного алгоритма.
Вот суть этого:
function getTables($like) {
// executes query "SHOW TABLES LIKE '$like%'" and return array
}
function tableSort(array $tables) {
usort($tables, "compareTables");
return $tables;
}
function compareTables($ta, $tb) {
global $db;
// foreign key test
foreach(array(
// if table A references table B, A is "greater than" B
array(
'TABLE' => $ta,
'REFERENCED' => $tb,
'VALUE' => 100
),
// if table B references table A, A is "smaller than" B
array(
'TABLE' => $tb,
'REFERENCED' => $ta,
'VALUE' => -100
),
) as $test) {
$res = $db->query("SELECT COUNT(*)
FROM information_schema.REFERENTIAL_CONSTRAINTS fk
WHERE fk.CONSTRAINT_SCHEMA = 'my_db'
AND fk.TABLE_NAME = '{$test['TABLE']}'
AND fk.REFERENCED_TABLE_NAME = '{$test['REFERENCED']}'")->field();
if($res > 0) {
return $test['VALUE'];
}
}
// se non vi sono chiavi esterne, applico conteggio campi ID
return countIds($ta) - countIds($tb);
}
function countIds($table) {
global $db;
// extract fields
$fields = $db->query("DESCRIBE $table");
// count ID fields
$count = 0;
// Listo per il numero di tutti i campi presenti nella tabella
while($field = $fields->fetch()) {
if (
$field['Field'] == 'revisione_documento'
|| substr($field['Field'], 0, 3) == "id_") {
++$count;
if($field['Field'] == 'revisione_documento') {
// stop counting now
break;
}
}
}
return $count;
}
Тем не менее, я нашел пару случаев, когда окончательный отсортированный массив имеет table_x
до table_y
даже если compareTables('table_x', 'table_y') > 0
, так что я ожидаю, что они будут отсортированы по-разному.
Это проблема с моим алгоритмом сортировки, или, скорее, с usort()
сам?
Вот фактический, хотя и довольно длинный пример:
// UNSORTED array
array (
0 => 'lin_98_3',
58 => 'lin_98_3_anamnesi_abitudini',
59 => 'lin_98_3_anamnesi_allergologica',
60 => 'lin_98_3_anamnesi_familiare',
61 => 'lin_98_3_anamnesi_fisiologica',
62 => 'lin_98_3_anamnesi_generale',
63 => 'lin_98_3_anamnesi_ginecologica',
64 => 'lin_98_3_anamnesi_handicap',
65 => 'lin_98_3_anamnesi_lavorativa',
66 => 'lin_98_3_anamnesi_lavorativa_lavori',
67 => 'lin_98_3_anamnesi_lavorativa_rischi',
68 => 'lin_98_3_anamnesi_patologica_familiare',
69 => 'lin_98_3_anamnesi_patologica_remota',
70 => 'lin_98_3_anamnesi_sportiva',
71 => 'lin_98_3_anamnesi_stupefacenti',
72 => 'lin_98_3_cartelle_cliniche',
73 => 'lin_98_3_dipendenti',
74 => 'lin_98_3_dipendenti_prescrizioni',
75 => 'lin_98_3_dosp',
76 => 'lin_98_3_esame_clinico',
77 => 'lin_98_3_esame_clinico_capo_collo',
78 => 'lin_98_3_esame_clinico_cardiovascolare',
79 => 'lin_98_3_esame_clinico_cute_mucose',
80 => 'lin_98_3_esame_clinico_digerente',
81 => 'lin_98_3_esame_clinico_endocrino',
82 => 'lin_98_3_esame_clinico_generale',
83 => 'lin_98_3_esame_clinico_muscolo_scheletrico',
84 => 'lin_98_3_esame_clinico_nervoso',
85 => 'lin_98_3_esame_clinico_osteoarticolare',
86 => 'lin_98_3_esame_clinico_respiratorio',
87 => 'lin_98_3_esame_clinico_tegumentario',
88 => 'lin_98_3_esame_clinico_uditivo',
89 => 'lin_98_3_esame_clinico_urogenitale',
90 => 'lin_98_3_liste',
91 => 'lin_98_3_liste_dipendenti',
92 => 'lin_98_3_malattie',
93 => 'lin_98_3_malattie_assenze',
94 => 'lin_98_3_malattie_visite',
95 => 'lin_98_3_medici_curanti',
96 => 'lin_98_3_protocolli',
97 => 'lin_98_3_protocolli_agenti',
98 => 'lin_98_3_protocolli_attrezzi',
99 => 'lin_98_3_protocolli_dipendenti',
100 => 'lin_98_3_protocolli_haccp_alimenti',
101 => 'lin_98_3_protocolli_impianti',
102 => 'lin_98_3_protocolli_macchine',
103 => 'lin_98_3_protocolli_mansioni',
104 => 'lin_98_3_protocolli_operazioni',
105 => 'lin_98_3_protocolli_opere_provvisionali',
106 => 'lin_98_3_protocolli_processi',
107 => 'lin_98_3_protocolli_rischi',
108 => 'lin_98_3_protocolli_vani',
109 => 'lin_98_3_protocolli_visite',
110 => 'lin_98_3_relazioni',
111 => 'lin_98_3_sgs_visite',
112 => 'lin_98_3_sgs_visite_parametri',
113 => 'lin_98_3_sgs_visite_prescrizioni',
114 => 'lin_98_3_studi_medici',
115 => 'lin_98_3_vaccinazioni',
116 => 'lin_98_3_vaccinazioni_somministrazioni',
117 => 'lin_98_3_visite',
118 => 'lin_98_3_visite_dipendenti',
)
// SORTED array
array (
0 => 'lin_98_3',
1 => 'lin_98_3_esame_clinico',
2 => 'lin_98_3_esame_clinico_generale',
3 => 'lin_98_3_esame_clinico_muscolo_scheletrico',
4 => 'lin_98_3_esame_clinico_nervoso',
5 => 'lin_98_3_esame_clinico_endocrino',
6 => 'lin_98_3_esame_clinico_digerente',
7 => 'lin_98_3_esame_clinico_cardiovascolare',
8 => 'lin_98_3_esame_clinico_cute_mucose',
9 => 'lin_98_3_esame_clinico_osteoarticolare',
10 => 'lin_98_3_esame_clinico_respiratorio',
11 => 'lin_98_3_protocolli',
12 => 'lin_98_3_relazioni',
13 => 'lin_98_3_studi_medici',
14 => 'lin_98_3_medici_curanti',
15 => 'lin_98_3_liste',
16 => 'lin_98_3_esame_clinico_capo_collo',
17 => 'lin_98_3_esame_clinico_uditivo',
18 => 'lin_98_3_esame_clinico_urogenitale',
19 => 'lin_98_3_visite',
20 => 'lin_98_3_esame_clinico_tegumentario',
21 => 'lin_98_3_anamnesi_ginecologica',
22 => 'lin_98_3_anamnesi_generale',
23 => 'lin_98_3_anamnesi_fisiologica',
24 => 'lin_98_3_anamnesi_familiare',
25 => 'lin_98_3_anamnesi_lavorativa',
26 => 'lin_98_3_anamnesi_abitudini',
27 => 'lin_98_3_dipendenti',
28 => 'lin_98_3_protocolli_opere_provvisionali',
29 => 'lin_98_3_protocolli_processi',
30 => 'lin_98_3_visite_dipendenti',
31 => 'lin_98_3_protocolli_macchine',
32 => 'lin_98_3_protocolli_mansioni',
33 => 'lin_98_3_protocolli_operazioni',
34 => 'lin_98_3_protocolli_rischi',
35 => 'lin_98_3_protocolli_vani',
36 => 'lin_98_3_sgs_visite',
37 => 'lin_98_3_sgs_visite_parametri',
38 => 'lin_98_3_sgs_visite_prescrizioni',
39 => 'lin_98_3_vaccinazioni',
40 => 'lin_98_3_protocolli_visite',
41 => 'lin_98_3_protocolli_impianti',
42 => 'lin_98_3_anamnesi_allergologica',
43 => 'lin_98_3_protocolli_attrezzi',
44 => 'lin_98_3_cartelle_cliniche',
45 => 'lin_98_3_anamnesi_patologica_familiare',
46 => 'lin_98_3_anamnesi_lavorativa_lavori',
47 => 'lin_98_3_anamnesi_patologica_remota',
48 => 'lin_98_3_anamnesi_stupefacenti',
49 => 'lin_98_3_dipendenti_prescrizioni',
50 => 'lin_98_3_protocolli_haccp_alimenti',
51 => 'lin_98_3_anamnesi_sportiva',
52 => 'lin_98_3_anamnesi_handicap',
53 => 'lin_98_3_dosp',
54 => 'lin_98_3_malattie',
55 => 'lin_98_3_protocolli_dipendenti',
56 => 'lin_98_3_protocolli_agenti',
57 => 'lin_98_3_malattie_visite',
58 => 'lin_98_3_liste_dipendenti',
59 => 'lin_98_3_malattie_assenze',
60 => 'lin_98_3_vaccinazioni_somministrazioni',
61 => 'lin_98_3_anamnesi_lavorativa_rischi',
)
однако таблица lin_98_3_esame_clinico
(индекс 1
в отсортированный массив) должен прийти после lin_98_3_dipendenti
(индекс 27
), поскольку compareTables('lin_98_3_esame_clinico', 'lin_98_3_dipendenti') == 1
Наконец, вот структура для lin_98_3_esame_clinico
а также lin_98_3_dipendenti
:
CREATE TABLE IF NOT EXISTS `lin_98_3_dipendenti` (
`id_dipendente` int(10) unsigned NOT NULL DEFAULT '0',
`id_azienda` int(10) unsigned NOT NULL DEFAULT '1',
`id_sede` int(10) unsigned NOT NULL DEFAULT '1',
`revisione_documento` int(10) unsigned NOT NULL DEFAULT '0',
-- countIds() stops here!
`id_sgs_medico` int(10) unsigned DEFAULT NULL,
`sgs_medico` varchar(255) DEFAULT NULL,
`esito` enum('Idoneo','Idoneo con prescrizioni','Idoneità parziale temporanea','Idoneità parziale permanente','Inidoneità temporanea','Inidoneità permanente','Sorveglianza sanitaria dopo cessazione esposizione') DEFAULT NULL,
`note` text,
`dosp_medico` varchar(255) DEFAULT NULL,
`dosp_esito` enum('Idoneo','Idoneo con prescrizioni','Inidoneità permanente','Sorveglianza sanitaria dopo cessazione esposizione') DEFAULT NULL,
`dosp_note` text,
`dosp_categoria` enum('Non esposto','Categoria A','Categoria B') DEFAULT NULL,
`flag_servizio_militare` tinyint(1) DEFAULT '0',
`flag_lavoro_notturno` tinyint(1) DEFAULT '0',
`attivita_extralavorative` set('Volontariato','Primo soccorso','Attività venatoria','Agricoltura/allevamento','Altro') DEFAULT NULL,
`grado_studio` enum('Nessuno','Licenza elementare','Licenza media','Diploma superiore','Laurea') DEFAULT NULL,
`medico_curante` varchar(255) DEFAULT NULL,
`indirizzo_medico` varchar(255) DEFAULT NULL,
`telefono_medico` varchar(255) DEFAULT NULL,
`email_medico` varchar(255) DEFAULT NULL,
`id_ultima_visita` int(10) unsigned DEFAULT NULL,
`dosp_id_ultima_visita` int(10) unsigned DEFAULT NULL,
`id_cartella_clinica` int(10) unsigned DEFAULT NULL,
`flag_modifiche` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id_dipendente`,`id_azienda`,`id_sede`,`revisione_documento`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `lin_98_3_esame_clinico` (
`id_esame_clinico` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_cartella_clinica` int(10) unsigned DEFAULT '0',
`id_azienda` int(10) unsigned NOT NULL DEFAULT '1',
`id_sede` int(10) unsigned NOT NULL DEFAULT '1',
`revisione_documento` int(10) unsigned NOT NULL DEFAULT '0',
-- countIds() stops here!
PRIMARY KEY (`id_esame_clinico`,`id_azienda`,`id_sede`,`revisione_documento`),
UNIQUE KEY `unique_id_cartella_clinica_lin_98_3_esame_clinico` (`id_cartella_clinica`,`id_azienda`,`id_sede`,`revisione_documento`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
для этих двух таблиц, countIds('lin_98_3_dipendenti') == 4
а также countIds('lin_98_3_esame_clinico') == 5
и между этими двумя не существует связи между внешними ключами.
Также, lin_98_3_cartelle_cliniche
(индекс 44
) должно быть до lin_98_3_anamnesi_generale
(индекс 22
), на самом деле есть внешний ключ в lin_98_3_anamnesi_generale
что ссылки lin_98_3_anamnesi_generale
а также compareTables('lin_98_3_anamnesi_generale', 'lin_98_3_cartelle_cliniche') == 100
Ваша функция сортировки по существу неверна, по крайней мере, в том смысле, что она не формирует правильный порядок. Могут быть циклы, то есть две таблицы, ссылающиеся друг на друга, и в этом случае ваша функция возвращает 100 как для (A, B), так и для (B, A).
Других решений пока нет …