简体   繁体   English

通过单个查询从相关数据库表中回显嵌套的JSON数组?

[英]Echo nested JSON array from related database tables with a single query?

I have two database tables that contain information about land contracts. 我有两个数据库表,其中包含有关土地合同的信息。 They are related with land_contract_annual_price.land_contract_id -> land_contract.land_contract_id . 它们与land_contract_annual_price.land_contract_id > land_contract.land_contract_id

Table 'land_contract' 表'land_contract' 在此处输入图片说明

Table 'land_contract_annual_price' 表“ land_contract_annual_price” 在此处输入图片说明

If a land contract has the value "Rörligt pris" in the field land_contract_price_type, there are related values in the table land_contract_annual_price . 如果土地合同在land_contract_price_type字段中的值为“Rörligtpris”,则表land_contract_annual_price有相关的值。 At the moment I'm doing two queries, one to each table. 目前,我正在执行两个查询,每个表一个。 I then merge the results and present the land contract as a nested JSON array like this: 然后,我合并结果并将土地合同显示为嵌套的JSON数组,如下所示:

Version 1 版本1

[  
 {  
  "land_contract_id":118,
  "land_contract_name":"Avtalsnamn",
  "location_id":71,
  "land_contract_link":"",
  "land_contract_notes":"",
  "land_owner_id":2,
  "land_contract_start_date":"2019-07-25",
  "land_contract_end_date":"2023-07-25",
  "land_contract_terminated":"false",
  "land_contract_payment_interval":"Halv\u00e5rsvis",
  "land_contract_price_type":"R\u00f6rligt \u00e5rspris",
  "land_contract_fixed_annual_price":null,
  "land_contract_annual_prices":[  
    {"year":1, "price":873.00},
    {"year":2, "price":77289.00},
    {"year":3, "price":8.00},
    {"year":4, "price":0.00},
    {"year":5, "price":8729.00}
  ]
 }
]

If a land contract has the value "Fast pris" in the field land_contract_price_type, there are no related values in the table land_contract_annual_price . 如果土地合同在land_contract_price_type字段中的值为“ Fast pris”,则表land_contract_annual_price中没有相关的值。 In that case I present the land contract like this (without the extra array at the end): 在那种情况下,我会像这样提交土地合同(末尾没有额外的数组):

Version 2 版本2

[
 {
  "land_contract_id":13,
  "land_contract_name":null,
  "location_id":null,
  "land_contract_link":"https:\/\/www.something.com\/preview\/Sl%C3%A4pvdam%20Edda\/Kddal\/Bddkta\/Besika%20Markavtal%20%20Halmstad%202016-03-08.pdf?role=personal",
  "land_contract_notes":"",
  "land_owner_id":null,
  "land_contract_start_date":"2016-03-08",
  "land_contract_end_date":"2026-03-08",
  "land_contract_terminated":"true",
  "land_contract_payment_interval":"\u00c5rsvis",
  "land_contract_price_type":"Fast \u00e5rspris",
  "land_contract_fixed_annual_price":"6000.00"
 }
]

What I didn't think of, is that this solution is bad when I'm fetchin ALL the land contracts. 我没有想到的是,当我获取所有土地合同时,这种解决方案是不好的。 If I'm going to do a second query to another table whenever a land contract has the value "Rörligt pris" in the field land_contract_price_type, I'm going to do hundreds of extra queries. 如果每当一份土地合同在land_contract_price_type字段中的值为“Rörligtpris”,我都会对另一个表进行第二次查询,那么我将进行数百个额外的查询。

Is there a way to create the nested JSON array with one (1) query when a land contract has the value "Rörligt pris" in the field land_contract_price_type? 当土地合同在land_contract_price_type字段中具有值“Rörligtpris”时,是否有一种方法可以使用一(1)个查询来创建嵌套的JSON数组?

Thanks! 谢谢!

Below is my current code. 下面是我当前的代码。

function read($pdo, $Id = null, $ResponseMessage = null) {

    $params = [];
    $array = [];

    $sql = "SELECT  lc.Id, lc.Name, lc.LocationId, l.Name AS LocationName, lc.Notes, lc.LandOwnerId, lo.Name AS LandOwnerName, lc.StartDate, lc.EndDate, lc.IsTerminated, lc.PaymentInterval, lc.PriceType, lc.FixedAnnualPrice, lc.Link, lc.Created, lc.Updated, lcap.AnnualPriceYear AS Year, lcap.AnnualPriceAmount AS Amount
            FROM LandContract lc
            LEFT JOIN Location l ON l.Id = lc.LocationId
            LEFT JOIN LandOwner lo ON lo.Id = lc.LandOwnerId
            LEFT JOIN LandContractAnnualPrice lcap ON lcap.LandContractId = lc.Id  
            ORDER BY lc.Id  DESC, lcap.AnnualPriceYear DESC
            ";
    if ($Id) {
        $sql .= 'WHERE lc.Id = ?';
        $params[] = $Id;
    }

    echo $sql;

    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    while ($row = $stmt->fetch()) {
        // Fields we want to extract from the select statement into the array 
        $select_fields = ['Id', 'Name', 'LocationId', 'LocationName', 'Link', 'Notes', 'LandOwnerId', 'LandOwnerName',
                            'StartDate', 'EndDate', 'IsTerminated', 'PaymentInterval', 
                            'PriceType', 'FixedAnnualPrice ', 'Created', 'Updated'];

        if (!isset($array[$row['Id']])) {
            // initialize the subarray if it has not been set already 
            $array[$row['Id']] = array_intersect_key($row, array_flip($select_fields));

            if ($row['Year'] != null) {
                $array[$row['Id']]['AnnualPrices'] = [];
            } else {
                $array[$row['Id']]['AnnualPrice'] = $row['FixedAnnualPrice'];
            }
        }

        if ($row['Year'] != null) {
            $array[$row['Id']]['AnnualPrices'][] = ['Year' => $row['Year'], 'Amount' => $row['Amount']];
        }

    }

    if (empty($array)) {
        $ResponseMessage = new ResponseMessage();
        $ResponseMessage->Status = 'Error';
        $ResponseMessage->Message = 'No results';
        echo json_encode($ResponseMessage, JSON_UNESCAPED_UNICODE);
        exit;
    }

    $Response = array();

    if ($ResponseMessage) {
        $Response['Status'] = $ResponseMessage->Status;
        $Response['Message'] = $ResponseMessage->Message;
    }

    $Response['LandContracts'] = array_values($array);

    echo json_encode($Response, JSON_UNESCAPED_UNICODE);

    $stmt = null;
}

You are better off using a JOIN query, and then structure your array from the result - having a query within a loop is often a very bad idea, and an indicator that you can use a JOIN instead. 最好使用JOIN查询,然后根据结果构造数组-在循环中进行查询通常是一个非常糟糕的主意,并且可以使用JOIN指示符。

You want to use a LEFT JOIN , joining them on the land_contract_id in both tables. 您想使用LEFT JOIN ,将它们加入两个表的land_contract_id中。

Then loop your results, and construct your array, which you can end up encoding into a JSON string once done. 然后循环您的结果,并构造您的数组,完成后就可以将其编码为JSON字符串。

$params = [];
$array = [];

$sql = "SELECT lc.*, 
               py.land_contract_annual_price_year AS `year`,  
               py.land_contract_annual_price_amount AS `amount`
        FROM land_contract AS lc
        LEFT JOIN land_contract_annual_price AS py 
            ON py.land_contract_id = lc.land_contract_id
        ";
if (isset($_POST['land_contract_id'])) {
    $sql .= 'WHERE lc.land_contract_id = ?';
    $params[] = $_POST["land_contract_id"];
}

$stmt = $pdo->prepare($sql);
$stmt->execute($params);
while ($row = $stmt->fetch()) {
    // Fields we want to extract from the select statement into the array 
    $select_fields = ['land_contract_id', 'land_contract_name', 'location_id', 'land_contract_link', 'land_contract_notes', 'land_owner_id', 
                        'land_contract_start_date', 'land_contract_end_date', 'land_contract_terminated', 'land_contract_payment_interval', 
                        'land_contract_price_type', 'land_contract_fixed_annual_price '];

    if (!isset($array[$row['land_contract_id']])) {
        // initialize the subarray if it has not been set already 
        $array[$row['land_contract_id']] = array_intersect_key($row, array_flip($select_fields));

        if ($row['year'] != null) {
            $array[$row['land_contract_id']]['land_contract_annual_prices'] = [];
        } else {
            $array[$row['land_contract_id']]['land_contract_annual_price'] = $row['land_contract_fixed_annual_price'];
        }
    }

    if ($row['year'] != null) {
        $array[$row['land_contract_id']]['land_contract_annual_prices'][] = ['year' => $row['year'], 'amount' => $row['amount']];
    }

}

if (empty($array)) {
    echo "No results";
    exit;
}

echo json_encode($array, JSON_UNESCAPED_UNICODE);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM