У меня есть запрос sql, выводящий несколько результатов из разных таблиц, одна из таблиц - "заказы" - содержит сведения о клиентах с order_id как PK, другая таблица - order_products - содержит каждый заказанный продукт со ссылкой на order_id и другой столбец как ПК.
В принципе, мне нужно знать, как запрашивать базу данных таким образом, чтобы каждый order_id отображался только один раз, причем данные из таблицы order_products добавлены в одну строку, даже если клиенты заказали более одного продукта в этой конкретной заказ.
В настоящее время данные клиента повторяются в результатах, если они заказали несколько разных продуктов - я знаю, почему это происходит (см. запрос), но не знаю, как получить результаты в требуемом формате. Моя лучшая идея была бы вложенным запросом, в котором результаты из order_products загружаются в массив или что-то в этом роде, но я даже не знаю, возможно ли это.
Я использую MySQL и PHP с результатами, которые затем выводятся в XML-документе. Если вам нужна дополнительная информация, пожалуйста, спросите!
SELECT uc_orders.order_id, uc_orders.order_total, uc_orders.primary_email,
uc_orders.delivery_first_name, uc_orders.delivery_last_name,
uc_orders.delivery_street1, uc_orders.delivery_street2, uc_orders.delivery_city,
uc_orders.delivery_zone, uc_orders.delivery_postal_code, uc_zones.zone_name,
uc_order_products.title, uc_order_products.price
FROM uc_orders
LEFT JOIN uc_zones ON uc_orders.delivery_zone = uc_zones.zone_id
LEFT JOIN uc_order_products ON uc_orders.order_id = uc_order_products.order_id
ORDER BY order_id
Один из основных принципов реляционных баз данных состоит в том, что столбцы не содержат составных данных, что означает отсутствие массивов. Он также называется " первая нормальная форма" (1NF). Если вы не хотите повторять информацию о заказе в запросе продукта, вы можете запускать два запроса, а не один, который получает заказы, а второй - продукты.
Поскольку результат запроса обрабатывается в любом случае, вы также можете позаботиться об агрегировании в PHP после получения результата. Сначала вы можете агрегировать:
$orders=array();
while ($row = $result->fetch()) {
if (! isset($orders[$row['order_id']])) {
$orders[$row['order_id']] = new Order($row);
} else {
$orders[$row['order_id']]->addProducts($row);
}
}
(предполагая подходящий класс Order) или совокупность в строке:
class OrderList {
...
function printXML($result) {
$currOrderID = null;
echo '<orders>'
while ($row = $result->fetch()) {
if ($currOrderID != $row['order_id']) {
$this->closeOrder();
$this->openOrder($row);
}
$this->printProduct($row);
}
$this->closeOrder();
echo '</orders>';
}
function openOrder($row) {
echo "<order id='$row[order_id]'><total>$row[order_total]</total>";
$this->printCustomer($row);
echo '<products>';
}
function printProduct($row) {
echo "<product><title>$row[title]</title><price>$row[price]</price></product>\n";
}
function closeOrder() {
echo '</products></order>';
}
function printCustomer($row) {
echo <<EOS;
<customer>
<email>$row[primary_email]</email>
<first_name>$row[delivery_first_name]</first_name>
...
EOS;
$this->printAddress($row);
echo '</customer>';
}
function printAddress($row) {
echo <<EOS;
<address>
<street line="1">$row[delivery_street1]</street>
<street line="2">$row[delivery_street2]</street>
...
</address>
EOS;
}
}
Конечно, особенности вышеизложенного не являются хорошим дизайном для производственного кода. Методы print*
(и даже печать заказов с помощью openOrder
и closeOrder
), вероятно, заслуживают того, чтобы быть классами OrderWriter, CustomerWriter, AddressWriter и ProductWriter. Вы также можете использовать XMLWriter, а не эхо.
Вы можете создать пользовательскую функцию, которая будет принимать идентификатор заказа и возвращать список упорядоченных продуктов в строке. Затем вместо соединения с вашей таблицей uc_order_products вы просто вызываете UDF. Надеюсь, это поможет.
Это процедурная задача и потребует обработки набора результатов с помощью PHP или другого языка (может быть процедура db, которая возвращает массив для вас).