SQL JOIN以数组

时间:2016-06-15 17:11:15

标签: php mysql pdo

我尝试在服务器端为前端制作一些不错的结构数据。

响应应如下所示:

    [
      {
        "id": "57484a7e0cdb86d125ebce9c",
        "wasCalled": true,
        "wasGood": false,
        "candidateName": "Tonia Santos",
        "positions": [
          {
            "positionId": "48asd4asd36",
            "positionName": "Pozicia1"
          },
          {
            "positionId": "954asd5as4d",
            "positionName": "Pozicia4"
          }
        ],
        "addedBy": "User1",
        "registered": "2014-11-30T07:13:27 -01:00"
      }
  ]

数据库结构:

  • 候选人:所有信息都有职位

    | id | wasCalled | wasGood | addedBy | firstName | lastName的

  • [li>

    candidates_positions:每行是一个用户和一个位置

    | id | candidateId | positionId | positionName

我如何尝试:

class getCandidates
{
    public function getFromDatabase(){
        try {
            $con = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
            $con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
            $sql = "SELECT * FROM candidates as c INNER JOIN candidates_positions as cp ON c.id=cp.candidateId;";
            $stmt = $con->prepare($sql);
            $stmt->execute();
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        }catch( PDOException $e ) {
            return $e->getMessage();
        }

    }

    public function createJson($data){
        return json_encode($data);
    }
}

实际创建的内容:

[{
    "id": "1",
    "firstName": "Tonia",
    "lastName": "Santos",
    "addedBy": "22",
    "wasCalled": "1",
    "wasGood": null,
    "candidateId": "1",
    "positionId": "1",
    "positionName": "Pozicia4"
},
{
    "id": "1",
    "firstName": "Tonia",
    "lastName": "Santos",
    "addedBy": "22",
    "wasCalled": "1",
    "wasGood": null,
    "candidateId": "1",
    "positionId": "1",
    "positionName": "Pozicia1"
}]

在没有对数据库进行多次选择和构建JSON的情况下,是否有一些很好的方法或最佳实践如何创建类似于此问题的JSON?

感谢您的任何建议

4 个答案:

答案 0 :(得分:2)

虽然您的问题已经解决,但确实看了下面的答案,但它更简洁明了。

答案:

利用MySQL的GROUP BYGROUP_CONCAT条款,随后更改您的查询,

SELECT c.*, GROUP_CONCAT(cp.positionId, '|', cp.positionName) as positions 
FROM candidates as c 
INNER JOIN candidates_positions as cp 
ON c.id=cp.candidateId 
GROUP BY c.id

以下是参考资料:

所以只需按以下方式更改getFromDatabase()方法,

public function getFromDatabase(){
    try {
        $con = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
        $con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
        $sql = "SELECT c.*, GROUP_CONCAT(cp.positionId, '|', cp.positionName) as positions FROM candidates as c INNER JOIN candidates_positions as cp ON c.id=cp.candidateId GROUP BY c.id";
        $stmt = $con->prepare($sql);
        $stmt->execute();

        $result_arr = array();
        while($result = $stmt->fetch(PDO::FETCH_ASSOC)){
            $tmp_arr = array('id' => $result['id'], 'wasCalled' => $result['wasCalled'], 'wasGood' => $result['wasGood'], 'addedBy' => $result['addedBy'], 'firstName' => $result['firstName'], 'lastName' => $result['lastName']);
            $positions = explode(",", $result['positions']);
            foreach($positions as $s){
                $components = explode("|", $s);
                $tmp_arr['positions'][] = array('positionId' => $components[0], 'positionName' => $components[1]);
            }
            $result_arr[] = $tmp_arr;
        }
        return $result_arr;
    }catch( PDOException $e ) {
        return $e->getMessage();
    }
}

稍后,您可以将返回的$result_arr数组传递给createJson()方法并在其上应用json_encode

答案 1 :(得分:1)

您可以通过更改createJson方法

来解析结果并获得所需的结果
    public function createJson($data){
        return_array = array();
        foreach($data as $val)
        {
          $return_array['id']= $val['id'];
          $return_array['candidateName']= $val['candidateName'];
          $return_array['wasCalled']= $val['wasCalled'];
          $return_array['wasGood']= $val['wasGood'];
          $return_array['addedBy']= $val['addedBy'];
          $return_array['positions'][] = array('positionId'=> $val['positionId'],'positionName'=>$val['positionName']);
        }
        return json_encode($return_array);
    }

答案 2 :(得分:1)

由于你为同一个人获得了多行,包含不同的位置,它可能看起来像(从我的脑袋里打字所以可能会出现一些错误,但试试看看):

 function prepare_result($data) {
  $result = [];
  foreach ($data as $record) {
    if (!isset($result[$record['candidateId']])) {
      $result[$record['candidateId']] = array(
        'id' => (int) $record['candidateId'],
        'wasCalled' => true,
        'wasGood' => false,
        'candidateName' => $record['firstName'] . " " . $record['lastName'],
        'addedBy' => 'no idea', // you need additional join i think, since your result returns only ID
        'registered' => 'no idea either', // same as above, original query returns no date
        'positions' => array(
          array(
            'positionId' => $record['positionId'],
            'positionName' => $record['positionName']
          )
        )
      );
    } else {
      $result[$record['candidateId']]['positions'][] = array(
        'positionId' => $record['positionId'],
        'positionName' => $record['positionName']
      );
    }
  }

  sort($result);

  return json_encode($result);
}

请注意registeredaddedBy的评论。

答案 3 :(得分:0)

你必须改变你的查询 我应该用

select ID, if (wasCalled=1,true,false) as wasCalled, if (wasGood=1,true,false) as wasGood,

concat(firstName,' ',lastName) as candidateName, positionID, positionName,addedBy

顺便说一下,这只是一个部分解决方案,你已经将这个与TheDeceptio的答案结合起来得到你的最终解决方案。 这是必要的,因为您没有候选名称字段,您必须创建。 此外,请注意您的addedBy返回一个ID,并且您希望该名称与该ID相关联,因此我推断您还有其他一些表必须提取此信息