[英]PHP usort() inconsistent result
I have created a PHP procedure which extract some table names from the database, and then sorts them based on custom algorithm. 我创建了一个PHP过程,该过程从数据库中提取了一些表名,然后根据自定义算法对它们进行排序。
Here is the gist of it: 这是要点:
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;
}
however, I have found a couple of cases where the final sorted array has table_x
before table_y
even if compareTables('table_x', 'table_y') > 0
, so that I would expect those to be sorted differently. 然而,我发现一对夫妇的情况下,其中最终排序的数组已经table_x
前table_y
即使compareTables('table_x', 'table_y') > 0
,所以我希望那些以不同的方式进行排序。
Is it an issue with my sorting algorithm, or rather with usort()
itself? 我的排序算法还是usort()
本身有问题吗?
Here is an actual, albeit quite long, example: 这是一个尽管很长的实际示例:
// 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',
)
however, the table lin_98_3_esame_clinico
(index 1
in sorted array) should come after lin_98_3_dipendenti
(index 27
), since compareTables('lin_98_3_esame_clinico', 'lin_98_3_dipendenti') == 1
然而,表lin_98_3_esame_clinico
(索引1
在排序后的数组)应该来后 lin_98_3_dipendenti
(指数27
),由于compareTables('lin_98_3_esame_clinico', 'lin_98_3_dipendenti') == 1
Finally, here is the structure for lin_98_3_esame_clinico
and lin_98_3_dipendenti
: 最后,这是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;
for these two tables, countIds('lin_98_3_dipendenti') == 4
and countIds('lin_98_3_esame_clinico') == 5
, and there is no foreign key relation between these two. 对于这两个表, countIds('lin_98_3_dipendenti') == 4
和countIds('lin_98_3_esame_clinico') == 5
,这两个表之间没有外键关系。
Also, lin_98_3_cartelle_cliniche
(index 44
) should be before lin_98_3_anamnesi_generale
(index 22
), in fact there is a foreign key in lin_98_3_anamnesi_generale
that references lin_98_3_anamnesi_generale
and compareTables('lin_98_3_anamnesi_generale', 'lin_98_3_cartelle_cliniche') == 100
此外, 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
Your sort function is essentially wrong at least in the aspect it does not form a proper order. 您的排序功能本质上是错误的,至少在它没有形成正确顺序方面。 There might be cycles, ie, two tables referring to each other, in which case your function returns 100 both for (A,B) and for (B,A). 可能存在周期,即两个表相互引用,在这种情况下,您的函数对于(A,B)和(B,A)都返回100。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.