Hoi, Hallo,

Allereerst bedankt als je me wilt helpen met het volgende probleem. Wellicht zit ik er helemaal naast...

Ik heb een stukje code geschreven om van alle landen over de wereld de bijbehorende provincies, districten, counties etc. erbij te zetten. Nu is het geval dat ik bij een land de districten onder hun Counties wil plaatsen. Hiervoor hebben de Counties een vaste code en de Districten heb ik zo gemaakt dat ze de bij behorende County codes bevatten. Echter is het probleem nu dat ik het niet voor elkaar krijg om de Districten onder de juiste County te zetten.

Dit is wat ik wil:
County 1
- District 1
- District 3
- District 6

County 2
- District 2
- District 4
- District 5

etc.

Maar ik krijg nu dit (voorbeeld, niet exacte namen):
County 1
County 2
District 1
District 2
District 3
District 4
District 5
District 6

Script hieronder laat de generated codes achter de Districten zien:

echo $row['subdivision_name']." - <i>".$row['category']."</i><br />";
$fixed = $row['subdivision_code'];
$generated = "";
//$generated = $row['alpha2']."-".$row['subdivision_parent'];
//echo "generated: ".$generated." <br /> ";
if (!empty($row['subdivision_parent'])) {
$generated = $row['alpha2']."-".$row['subdivision_parent'];
$fixed = "";
echo "generated: ".$generated." <br /> ";
}

Heeft iemand een idee hoe ik dit kan aanpakken?
Indien meer info nodig is hoor ik het graag.
Je wilt dus een multi-level lijststructuur? Waarbij je feitelijk oneindig veel levels onder je parent hebt?
Dan moet je deze genormaliseerd opslaan, en recursief ophalen.

Dus een lijst zoals; Europa, Benelux, Nederland, Noord-Holland, Alkmaar (gemeente), Alkmaar.


<?php
// get all menuitems with 1 query
$result = mysqli_query($con,"
    SELECT
        id, parentId, name
    FROM
        menu
    ORDER BY
        parentId, name
");

// prepare special array with parent-child relations
$menuData = array(
    'items' => array(),
    'parents' => array()
);

while ($menuItem = mysqli_fetch_assoc($result))
{
    $menuData['items'][$menuItem['id']] = $menuItem;
    $menuData['parents'][$menuItem['parentId']][] = $menuItem['id'];
}

// menu builder function, parentId 0 is the root
function buildMenu($parentId, $menuData)
{
    $html = '';

    if (isset($menuData['parents'][$parentId]))
    {
        $html = '<ul>';
        foreach ($menuData['parents'][$parentId] as $itemId)
        {
            $html .= '<li>' . $menuData['items'][$itemId]['name'];

            // find childitems recursively
            $html .= buildMenu($itemId, $menuData);

            $html .= '</li>';
        }
        $html .= '</ul>';
    }

    return $html;
}

// output the menu
echo buildMenu(0, $menuData);
?>




Bron:
https://crisp.tweakblogs.net/blog/317/

PS: Je bedoelt Countries (land)?
Ofwel je ordent de resultaten in je database-query -aangenomen dat $row een resultaatrij van een query is- met een ORDER BY clause, of je bouwt in PHP een kleine datastructuur zodat je daar (volg)orde aanbrengt in de resultaten.

Dit is een relatief eenvoudig sorteerprobleem lijkt mij, daarna is het een kwestie van de resultaten achter elkaar uitdraaien.
Bedankt voor je reactie - Ariën -,

Ik heb je script bekeken, maar moet ik uit je reactie concluderen dat het niet mogelijk is om met gegenereerde codes (child) naar een parent te leiden?

County (fixed code)
District (generated code)

Voorbeeld:
County - AL-01 (uit database)
District - AL-01 (deze AL-01 is gegenereerd)

Hieronder de volledige script:

<style>
.success {
border: 1px solid lime;
border-radius: 5px;
font: 12px verdana;
color: #000;
background-color: lime;
display: inline-block;
}
.failed {
border: 1px solid red;
border-radius: 5px;
font: 12px verdana;
color: #000;
background-color: red;
display: inline-block;
}
</style>
<?php
$servername = "";
$username = "";
$password = "";
$dbname = "";

// Create connection
$conn = mysqli_connect($servername, $username, $password, $dbname);

// Check connection
if (!$conn) {
die("<div class=\"failed\">Connection failed: ".mysqli_connect_error()."</div><br /><br />");
}
echo "<div class=\"success\">Connected successfully</div><br /><br />";

// Change character set to utf8
if (!$conn->set_charset("utf8")) {
printf("Error loading character set utf8: %s\n<br />", $conn->error);
} else {
printf("Current character set: %s\n<br />", $conn->character_set_name());
}

// SQL join
$sql = "SELECT * FROM `iso3166-1`
LEFT JOIN `iso3166-2` ON `iso3166-1`.`numeric` WHERE `iso3166-1`.`numeric` = `iso3166-2`.`numeric`
UNION -- use UNION ALL to retain common rows
SELECT * FROM `iso3166-1`
RIGHT JOIN `iso3166-2` ON `iso3166-1`.`numeric` WHERE `iso3166-1`.`numeric` = `iso3166-2`.`numeric`";

// Get SQL results
$result = mysqli_query($conn, $sql);

if (!$result) {
echo "Could not successfully run query ($sql) from DB: ".mysqli_error($conn)."<br />";
exit;
}

$check_previous = "";
$same = false;

if (mysqli_num_rows($result) == 0) {
echo "No rows found, nothing to print so am exiting<br />";
exit;
}

// While Loop
while ($row = mysqli_fetch_assoc($result)) {

$shortname = $row['shortname'];

if ($shortname!==$check_previous) {
echo "<b>".$shortname."</b><br />";
} else {
echo "";
}

$check_previous="";

if ($same==true) {
// we know $same is true but are they really the same?
if ($check_previous=$shortname) {
$same=true;
//echo $same;
} else {
$same=false;
$row['shortname']="";
//echo $same;
}
} else {
// we are not sure that is it the same... need check
if ($check_previous=$shortname) {
//now we are 100% sure it is the same
$same=true;
}
if ($check_previous!=$shortname) {
//now we are 100% sure it is NOT the same
$same=false;
}
}

// Put Districts (with Parent Codes) in County
echo $row['subdivision_name']." - <i>".$row['category']."</i><br />";
$fixed = $row['subdivision_code'];
$generated = "";
//$generated = $row['alpha2']."-".$row['subdivision_parent'];
//echo "generated: ".$generated." <br /> ";
if (!empty($row['subdivision_parent'])) {
$generated = $row['alpha2']."-".$row['subdivision_parent'];
$fixed = "";
echo "generated: ".$generated." <br /> ";
}
}

mysqli_free_result($result);
mysqli_close($conn);
?>


[size=xsmall]Toevoeging op 06/04/2019 13:43:01:[/size]

Thomas van den Heuvel, ik begrijp je maar dit kan niet als de code pas in een While Loop word gegenereerd.

Adoptive Solution, ja zoiets, alhoewel ik het een beetje anders wil hebben in design ;-) Daarnaast is mijn probleem nu echter of ik gegenereerde child codes kan linken aan gefixeerde codes
= is een toekenning
== is een vergelijking
=== is een typegevoelige vergelijking

Dus $check_previous=$shortname in een if-statement lijkt mij sowieso niet kloppen.
Een toekenning zelf heeft ook een resultaat. Dit kan mogelijk tot gevolg hebben dat een if-statement niet doet wat je zou verwachten.

Het resultaat van $test = 'x' is 'x'. Als je dus zoiets doet:
<?php
$test = 'a';
if ($test = 'b') {
    // dit gedeelte wordt uitgevoerd
}
?>

Immers, het resultaat van de toekenning $test = 'b' is 'b' en dit is ongelijk aan een false-achtige waarde, dus het if-statement voldoet en het bijbehorende codeblok wordt uitgevoerd.

Controleer je echter op de volgende wijze:
<?php
$test = 'a';
if ($test == 'b') {
    // dit gedeelte wordt niet uitgevoerd
}
?>

Immers $test is ongelijk aan 'b'.
Ik heb de genereerde codes eruit gehaald en de database genormaliseerd.
Echter ik krijg ORDER BY hier niet aan het werk... Kan ik ORDER BY wel gebruiken by JOIN's?

(Ter info: `iso3166-2`.`subdivision_parent` bevat nu dezelfde code (is hier dus een Child) dat een code in `iso3166-2`.`subdivision_code` (=Parent) gekoppeld kan worden)

<?php
$sql = "SELECT * FROM `iso3166-1`
LEFT JOIN `iso3166-2` ON `iso3166-1`.`numeric` WHERE `iso3166-1`.`numeric` = `iso3166-2`.`numeric`
UNION -- use UNION ALL to retain common rows
SELECT * FROM `iso3166-1`
RIGHT JOIN `iso3166-2` ON `iso3166-1`.`numeric` WHERE `iso3166-1`.`numeric` = `iso3166-2`.`numeric`
ORDER BY `iso3166-2`.`subdivision_parent`";
?>
Op basis van je code heb ik wat data erbij gezocht.

http://kejser.org/resources/free-data/free-data-countries-world/
https://www.ip2location.com/free/iso3166-2

Wat tabellen aangemaakt:

CREATE TABLE `iso3166_1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `numeric` int(11) DEFAULT NULL,
  `Alpha2Code` varchar(4) DEFAULT NULL,
  `Alpha3Code` varchar(4) DEFAULT NULL,
  `CountryName` varchar(128) DEFAULT NULL,
  `TopLevelDomain` varchar(5) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `numeric` (`numeric`),
  KEY `Alpha2Code` (`Alpha2Code`),
  KEY `CountryName` (`CountryName`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;



CREATE TABLE `iso3166_2` (
  `country_code` char(2) DEFAULT NULL,
  `subdivision_name` varchar(128) DEFAULT NULL,
  `subdivision_code` varchar(10) DEFAULT NULL,
  KEY `idx_country_code` (`country_code`),
  KEY `idx_region_name` (`subdivision_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


En de data geïmporteerd.

De veldnaam 'subdivision_code' is al compleet, bijvoorbeeld :

AD	Andorra la Vella	AD-07


Indien de landencode in de subdivision_code onbreekt, dan zou het er zo uit kunnen zien :

AD	Andorra la Vella	07


Omdat ik uit je php code opmaak dat je de landencode en de subdivision code nog moet samenvoegen, kan je iets dergelijk al in MySQL doen.

SELECT
	UPPER(Alpha2Code) AS Code,
	CountryName AS Name,
	CONCAT(Alpha2Code,'-',subdivision_code) AS SubCode,
	subdivision_name AS Subdivision
FROM
	iso3166_1
LEFT JOIN
	iso3166_2
ON
	Alpha2Code = country_code
WHERE
	Alpha2Code >= 'MA'
AND
	Alpha2Code <= 'MZ'
ORDER BY
	Name, Subdivision


Het resulaat zou er dan zo uit kunnen zien :

Code	Name	SubCode	Subdivision
MA	Morocco	MA-05	Beni-Mellal-Khenifra
MA	Morocco	MA-06	Casablanca-Settat
MA	Morocco	MA-08	Draa-Tafilalet

Adoptive Solution, ik heb met je code zitten spelen. Je hebt een mooie manier gevonden. Echter krijg ik het niet voor elkaar met mijn eigen data. Daarnaast zie ik geen COUNTY (dat is geen COUNTRY) en zie ik geen onderscheid tussen de subdivisions (zoals COUNTY, DISTRICT, PROVINCE etc.). Dat laatste is nou net wat ik zocht...

Ik ga jullie mijn voorbeeld verbeteren met data voorbeelden. Hopelijk helpt dat...

Voorbeeld: bij een land waarbij COUNTIES en de daarbij horende DISTRICTEN bekend zijn:

COUNTRY
- COUNTY
-- DISTRICT

Zo komt het bijvoorbeeld eruit te zien:

Albania
- Berat - County
-- Berat - District
-- Kuçovë - District
-- Skrapar - District
- Dibër - County
- Durrës - County
etc...

Voorbeeld: bij een land waarbij alleen PROVINCIES bekend zijn (waarbij later de gemeentes per provincies erbij komen):

COUNTRY
- PROVINCE
(-- COMMUNITIES) // De gemeentes

Zo komt het bijvoorbeeld eruit te zien:

Afghanistan
- Badakhsh?n - Province
- B?dgh?s - Province
- Baghl?n - Province
- Balkh - Province
- B?my?n - Province
- D?ykund? - Province
etc...

Zo kan elk land een andere indeling hebben, maar dat is nu even ter info voor jullie.

Mijn database structuren zijn:

iso3166-1 (Tabelnaam)
- id - int(11) -> 1 (oplopend)
- history - int(1) -> 0 (of 1 wanneer dit record is verwijderd)
- shortname - varchar(255) -> Afghanistan
- nativename - varchar(255) -> ?????????
- alpha2 - char(2) -> AF
- alpha3 - char(3) -> AFG
- numeric - char(3) -> 004

iso3166-2
- id - int(11) -> 47 (oplopend)
- history - int(1) -> 0 (of 1 wanneer dit record is verwijderd)
- numeric - char(3) -> 008
- subdivision_code - varchar(6) -> AL-BR
- subdivision_name - varchar(255) -> Berat
- category - varchar(255) -> District
- subdivision_parent - char(5) -> AL-01

mijn volledige php code staat in een bericht hierboven.
Hopend dat dit meer helpt. Fijn weekend allemaal.

[size=xsmall]Toevoeging op 07/04/2019 13:46:12:[/size]

Ter info: de nativenaam word hier weergegeven met ?????????. Echter zijn dit speciale characters.

Reageren