问题描述
在我的科目表中,我按学期和月份列出了所有学生的课程,并给出了每个月的分数
in my subjects table i have all student's classes by semester and month with each month's points
[
{
"id": "4", - this is the subject id
"userid": "1",
"name": "bio",
"semester": "3", - semester
"month": "5", - the month
"points": "652" - points of this class
"time": "2017-06-18 22:45:04"
},
{
"id": "3", - this is the subject id
"userid": "1",
"name": "math",
"semester": "3", - semester
"month": "4", - the month
"points": "33" - points of this class
"time": "2017-05-15 22:45:04"
},
{
"id": "2", - this is the subject id
"userid": "1",
"name": "chem",
"semester": "1", - semester
"month": "3", - the month
"points": "22" - points of this class
"time": "2017-04-11 22:45:04"
},
{
"id": "1", - this is the subject id
"userid": "1",
"name": "phy",
"semester": "1", - semester
"month": "2", - the month
"points": "10" - points of this class
"time": "2017-02-10 22:45:04"
}
]
这就是我尝试过的
$sql = "SELECT users.id userid,users.name username,subjects.id subjectsid, subjects.name subjectname, subjects.points activepts FROM tbusers AS users INNER JOIN tbsubjects AS subjects ON users.id = subjects.userid WHERE users.id = '$userid' ORDER BY subjects.time DESC";
try {
$db = new db();
$db = $db->connect();
$stmt = $db->prepare($sql);
$stmt->execute();
$user = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
if(empty($user)) {
$response->getBody()->write
('
{
"error":
{
"message":"Invalid"
}
}');
} else {
$response->getBody()->write(json_encode($user));
}
} catch(PDOException $e) {}
我从查询中获得的当前输出是每个查询的多个响应,因为fetchAll
我可以将其更改为fetch
,但不会获取其他数据
the current output i am getting from my query is multiple responses for each because of fetchAll
i could just change it to fetch
but it won't get the other data
[
{
"userid": "1",
"username": "joe",
"subjectid": "4",
"subjectname": "bio",
"activepts": "652"
},
"userid": "1",
"username": "joe",
"subjectid": "3",
"subjectname": "math",
"activepts": "33"
},
"userid": "1",
"username": "joe",
"subjectid": "2",
"subjectname": "chem",
"activepts": "22"
},
"userid": "1",
"username": "joe",
"subjectid": "1",
"subjectname": "phy",
"activepts": "10"
}
]
我的问题是我如何将它们合并为一个响应,并在预期的输出中返回以下数据(我在每个字段中添加了一些描述以对其进行解释)
my question is how can i merge them into one response and return the below data in the expected output (i have added a little description of each field to explain it)
预期产量
[
{
"userid": "1", - from users table
"username": "joe", - from users table
"subjectsid": "1", - first subject id for the student in this case the one for phy
"subjectname": "bio", - current subject name
"activepts": "652", - points of current month
"totalpts": "717", - total points of all subjects for this student
"sem1": "32", - total points of all subjects for this student of semester 1
"sem2": "0", - total points of all subjects for this student of semester 2
"sem3": "685", - total points of all subjects for this student of semester 3
}
]
推荐答案
问题是,您想要获取主题,而不是学生.因此,我反转了FROM和LEFT JOIN.因此,当您需要主题列表时,您将从SELECT ... FROM主题开始.然后,如果您需要每个主题的其他详细信息(例如用户名等),请应用LEFT JOIN,这意味着:将所有必需的详细信息(用户名等)加入LEFT表的每个记录,例如主表(在您的情况下是表主题").
The thing is, you want to fetch the subjects, not the students. So, I inverted the FROM and LEFT JOIN. So, when you want a list of subjects, you are starting with SELECT ... FROM subjects. Then, if you need other details to each subject (like username, etc), you apply LEFT JOIN, which means: JOIN all the needed details (username, etc) to each record of the LEFT table, e.g. of the main table (in you case is table "subjects").
祝你好运!
<?php
try {
$dbAdapter = new DbAdapter();
$connection = $dbAdapter->connect();
/*
* I renamed user id variable (from $userId to $userid1) in order to show you that you can
* provide more users if you wish. Then you just have to extend
* the WHERE clause in the sql statement and the bindings array.
*/
$userid1 = 1;
/*
* The sql statement - it will be prepared.
*
* ======================================================
* I'm not sure about the following fields - because you
* didn't provide proper selection criteria for them:
*
* 1) "subjectsid": "1", - first subject id for the student in this case the one for phy
* 2) "subjectname": "bio", - current subject name
* ======================================================
*/
$sql = 'SELECT
subjects.userid,
users.name AS username,
(
SELECT id
FROM tbsubjects
WHERE userid = subjects.userid
ORDER BY id ASC
LIMIT 1
) AS subjectsid,
(
SELECT name
FROM tbsubjects
WHERE
userid = subjects.userid
ORDER BY time DESC
LIMIT 1
) AS subjectname,
(
SELECT IFNULL(SUM(points), 0)
FROM tbsubjects
WHERE
userid = subjects.userid
AND month = DATE_FORMAT(NOW(), "%c")
) AS activepts,
IFNULL(SUM(subjects.points), 0) AS totalpts,
(
SELECT IFNULL(SUM(points), 0)
FROM tbsubjects
WHERE
userid = subjects.userid
AND semester = 1
) AS sem1,
(
SELECT IFNULL(SUM(points), 0)
FROM tbsubjects
WHERE
userid = subjects.userid
AND semester = 2
) AS sem2,
(
SELECT IFNULL(SUM(points), 0)
FROM tbsubjects
WHERE
userid = subjects.userid
AND semester = 3
) AS sem3
FROM
tbsubjects AS subjects
LEFT JOIN tbusers AS users ON users.id = subjects.userid
WHERE subjects.userid = :userid1
GROUP BY subjects.userid
ORDER BY subjects.time DESC';
/*
* The input parameters list for the prepared sql statement.
*/
$bindings = array(
':userid1' => $userid1,
);
/*
* Prepare and validate the sql statement.
*
* --------------------------------------------------------------------------------
* If the database server cannot successfully prepare the statement, PDO::prepare()
* returns FALSE or emits PDOException (depending on error handling settings).
* --------------------------------------------------------------------------------
*/
$statement = $connection->prepare($sql);
if (!$statement) {
throw new UnexpectedValueException('The sql statement could not be prepared!');
}
/*
* Bind the input parameters to the prepared statement.
*
* -----------------------------------------------------------------------------------
* Unlike PDOStatement::bindValue(), when using PDOStatement::bindParam() the variable
* is bound as a reference and will only be evaluated at the time that
* PDOStatement::execute() is called.
* -----------------------------------------------------------------------------------
*/
foreach ($bindings as $key => $value) {
$bound = $statement->bindValue(
getInputParameterName($key)
, $value
, getInputParameterDataType($value)
);
if (!$bound) {
throw new UnexpectedValueException('An input parameter can not be bound!');
}
}
/*
* Execute the prepared statement.
*
* ------------------------------------------------------------------
* PDOStatement::execute returns TRUE on success or FALSE on failure.
* ------------------------------------------------------------------
*/
$executed = $statement->execute();
if (!$executed) {
throw new UnexpectedValueException('The prepared statement could not be executed!');
}
/*
* Fetch users list - array of objects.
*/
$users = $statement->fetchAll(PDO::FETCH_OBJ);
if ($users === FALSE) {
throw new UnexpectedValueException('Fetching users list failed!');
}
/*
* Close connection.
*/
$connection = NULL;
/*
* Handle results.
*/
if (empty($users)) {
$response->getBody()->write(
'{
"error": {
"message":"Invalid"
}
}'
);
} else {
$response->getBody()->write(json_encode($users));
}
} catch (PDOException $exc) {
echo $exc->getMessage();
// $logger->log($exc);
exit();
} catch (Exception $exc) {
echo $exc->getMessage();
// $logger->log($exc);
exit();
}
/**
* Get the name of an input parameter by its key in the bindings array.
*
* @param int|string $key The key of the input parameter in the bindings array.
* @return int|string The name of the input parameter.
*/
function getInputParameterName($key) {
return is_int($key) ? ($key + 1) : (':' . ltrim($key, ':'));
}
/**
* Get the PDO::PARAM_* constant, e.g the data type of an input parameter, by its value.
*
* @param mixed $value Value of the input parameter.
* @return int The PDO::PARAM_* constant.
*/
function getInputParameterDataType($value) {
$dataType = PDO::PARAM_STR;
if (is_int($value)) {
$dataType = PDO::PARAM_INT;
} elseif (is_bool($value)) {
$dataType = PDO::PARAM_BOOL;
}
return $dataType;
}
对于我的项目,我开发了一个DbAdapter类.方法名称不言自明.因此,每个网页内没有更多的spagetti代码:-)而是:
For my projects I developed a DbAdapter class. The method names are self-explanatory. So, no more spagetti code inside each web page :-) But just:
- sql语句,
- 绑定数组,
- 对数据库适配器中相应方法的调用和
- 从数据库断开连接行
您的问题的解决方案如下所示:
The solution to your question would look like this:
<?php
//***********************************************************************************
// Put this in a php file (like db.php) to include whereever you need db data access.
//***********************************************************************************
//
// Db configs.
define('DB_HOST', '...');
define('DB_PORT', 3306);
define('DB_DBNAME', '...');
define('DB_CHARSET', 'utf8');
define('DB_USERNAME', '...');
define('DB_PASSWORD', '...');
define('DB_DRIVER_NAME', 'mysql');
// Create db adapter.
$dbAdapter = new DbAdapter(DB_HOST, DB_DBNAME, DB_USERNAME, DB_PASSWORD, DB_PORT, DB_CHARSET);
//***********************************************************************************
$userid1 = 1;
// Sql statement.
$sql = 'SELECT ... FROM ... WHERE subjects.userid = :userid1 GROUP BY ... ORDER BY ...';
// Input parameters.
$bindings = array(
':userid1' => $userid1,
);
// Fetch users.
$users = $dbAdapter->fetchAll($sql, $bindings);
// Disconnect from db.
$dbAdapter->disconnect();
/*
* Handle results.
*/
if (empty($users)) {
//...
} else {
//...
}
要调用的适配器方法是public
个方法:
The adapter methods to call are the public
ones:
- 连接:连接到数据库,例如创建一个PDO实例,例如创建数据库连接.
- 断开连接:与数据库断开连接.
- fetchAll :一次获取更多记录.返回数组的数组.因此,每个元素都是对应于db记录的数组.
- fetchOne :仅获取一条记录.
- fetchColumn :获取列值.
- 更新:执行UPDATE查询.返回受影响的行数.
- 删除:执行DELETE查询.返回受影响的行数.
- 插入:执行INSERT查询.返回最后一个插入ID.
- getLastInsertId :返回执行INSERT操作后的最后一个插入ID.
- connect: Connects to the database, e.g. creates a PDO instance, e.gcreates a db connection.
- disconnect: Disconnects from the database.
- fetchAll: Fetches more records at once. Returns an array of arrays. So, each element is an array corresponding to a db record.
- fetchOne: Fetches only one record.
- fetchColumn: Fetches a column value.
- update: Performs an UPDATE query. Returns the number of affected rows.
- delete: Performs a DELETE query. Returns the number of affected rows.
- insert: Performs an INSERT query. Returns the last insert id.
- getLastInsertId: Returns the last insert id after an INSERT operation is performed.
仅此而已:-)
<?php
/*
* Database adapter.
*/
/**
* Database adapter.
*/
class DbAdapter {
/**
* Connection configs.
*
* @var array
*/
private $connectionConfigs;
/**
* Database connection.
*
* @var PDO
*/
private $connection;
/**
* PDO statement.
*
* @var PDOStatement
*/
private $statement;
/**
*
* @param string $host [optional] Host.
* @param string $dbname [optional] Database name.
* @param string $username [optional] User name.
* @param string $password [optional] Password.
* @param string $port [optional] Port.
* @param string $charset [optional] Character set.
* @param string $driverName [optional] Driver name.
* @param array $driverOptions [optional] Driver options.
* @return string DSN string.
*/
public function __construct($host = '', $dbname = ''
, $username = '', $password = '', $port = 3306, $charset = 'utf8', $driverName = 'mysql'
, $driverOptions = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => FALSE,
PDO::ATTR_PERSISTENT => TRUE,
)) {
$this->setConnectionConfigs(array(
'host' => $host,
'dbname' => $dbname,
'username' => $username,
'password' => $password,
'port' => $port,
'charset' => $charset,
'driverName' => $driverName,
'driverOptions' => $driverOptions,
));
}
/**
* Connect to db, e.g. create a PDO instance.
*
* @return $this
* @throws PDOException
*/
public function connect() {
if (!isset($this->connection) || !$this->connection) {
try {
$this->connection = new PDO(
$this->createDsn(
$this->connectionConfigs['host']
, $this->connectionConfigs['dbname']
, $this->connectionConfigs['port']
, $this->connectionConfigs['charset']
, $this->connectionConfigs['driverName']
)
, $this->connectionConfigs['username']
, $this->connectionConfigs['password']
, $this->connectionConfigs['driverOptions']
);
} catch (PDOException $pdoException) {
echo $pdoException->getMessage();
exit();
}
}
return $this;
}
/**
* Disconnect from db.
*
* @return $this
*/
public function disconnect() {
$this->connection = NULL;
return $this;
}
/**
* Create a DSN string.
*
* @param string $host Host.
* @param string $dbname Database name.
* @param string $port Port.
* @param string $charset Character set.
* @param string $driverName Driver name.
* @return string DSN string.
*/
private function createDsn($host, $dbname, $port, $charset, $driverName) {
switch ($driverName) {
default: // mysql
$dsn = sprintf('%s:host=%s;port=%s;dbname=%s;charset=%s'
, $driverName
, $host
, $port
, $dbname
, $charset
);
break;
}
return $dsn;
}
/**
* Fetch data by executing a SELECT sql statement.
*
* @param string $sql Sql statement.
* @param array $bindings [optional] Input parameters.
* @param integer $fetchMode [optional] Fetch mode for a PDO statement.
* Must be one of the PDO::FETCH_* constants.
* @param mixed $fetchArgument [optional] Fetch argument for a PDO statement.
* @param array $fetchConstructorArguments [optional] Constructor arguments for a PDO statement
* when fetch mode is PDO::FETCH_CLASS.
* @return array An array containing the rows in the result set, or FALSE on failure.
* @throws UnexpectedValueException
*/
public function fetchAll($sql, array $bindings = array(), $fetchMode = PDO::FETCH_ASSOC, $fetchArgument = NULL, array $fetchConstructorArguments = array()) {
$this
->prepareStatement($sql)
->bindInputParameters($bindings)
->executePreparedStatement()
;
try {
if (isset($fetchArgument)) {
$data = $this->getStatement()->fetchAll($fetchMode, $fetchArgument, $fetchConstructorArguments);
} else {
$data = $this->getStatement()->fetchAll($fetchMode);
}
if ($data === FALSE) {
throw new UnexpectedValueException('Fetching data failed!');
}
return $data;
} catch (Exception $exception) {
echo $exception->getMessage();
exit();
}
}
/**
* Fetch the next row from the result set by executing a SELECT sql statement.
* The fetch mode property determines how PDO returns the row.
*
* @param string $sql Sql statement.
* @param array $bindings [optional] Input parameters.
* @param integer $fetchMode [optional] Fetch mode for a PDO statement.
* Must be one of the PDO::FETCH_* constants.
* @param integer $fetchCursorOrientation [optional] For a PDOStatement object representing
* a scrollable cursor, this value determines which row will be returned to the caller.
* @param integer $fetchCursorOffset [optional] The absolute number of the row in the result
* set, or the row relative to the cursor position before PDOStatement::fetch() was called.
* @return array An array containing the next row in the result set, or FALSE on failure.
* @throws Exception
*/
public function fetchOne($sql, array $bindings = array(), $fetchMode = PDO::FETCH_ASSOC, $fetchCursorOrientation = PDO::FETCH_ORI_NEXT, $fetchCursorOffset = 0) {
$this
->prepareStatement($sql)
->bindInputParameters($bindings)
->executePreparedStatement()
;
try {
/*
* =========================================================
* NB:
* =========================================================
* PDOStatement::fetch returns FALSE not only on failure,
* but ALSO when no record is found! This is a BUG. That's
* why I made the try-catch block: maybe on failure will
* throw an exception.
*
* Instead, PDOStatement::fetchAll returns FALSE on failure,
* but an empty array if no record is found. This is the
* correct behaviour.
* =========================================================
*/
$data = $this->getStatement()->fetch($fetchMode, $fetchCursorOrientation, $fetchCursorOffset);
return $data;
} catch (Exception $exception) {
echo $exception->getMessage();
exit();
}
}
/**
* Returns a single column from the next row of a result set
* or FALSE if there are no more rows.
*
* =================================================================
* Note:
* -----
* PDOStatement::fetchColumn() should not be used to retrieve
* boolean columns, as it is impossible to distinguish a value
* of FALSE from there being no more rows to retrieve.
* Use PDOStatement::fetch() instead.
*
* Warning:
* --------
* There is no way to return another column from the same row if you
* use PDOStatement::fetchColumn() to retrieve data.
* =================================================================
*
* @param string $sql Sql statement.
* @param array $bindings [optional] Input parameters.
* @param integer $columnNumber [optional] 0-indexed number of the
* column you wish to retrieve from the row. If no value is supplied,
* PDOStatement::fetchColumn() fetches the first column.
* @return mixed A single column from the next row of a result set
* or FALSE if there are no more rows.
* @throws Exception
*/
public function fetchColumn($sql, array $bindings = array(), $columnNumber = 0) {
$this
->prepareStatement($sql)
->bindInputParameters($bindings)
->executePreparedStatement()
;
try {
return $this->getStatement()->fetchColumn($columnNumber);
} catch (Exception $exception) {
echo $exception->getMessage();
exit();
}
}
/**
* Store data by executing an INSERT sql statement.
*
* @param string $sql Sql statement.
* @param array $bindings [optional] Input parameters.
* @return int Last insert id.
*/
public function insert($sql, array $bindings = array()) {
$this
->prepareStatement($sql)
->bindInputParameters($bindings)
->executePreparedStatement()
;
return $this->getLastInsertId();
}
/**
* Update data by executing an UPDATE sql statement.
*
* @param string $sql Sql statement.
* @param array $bindings [optional] Input parameters.
* @return int Number of affected rows.
*/
public function update($sql, array $bindings = array()) {
$this
->prepareStatement($sql)
->bindInputParameters($bindings)
->executePreparedStatement()
;
return $this->getStatement()->rowCount();
}
/**
* Delete data by executing a DELETE sql statement.
*
* @param string $sql Sql statement.
* @param array $bindings [optional] Input parameters.
* @return int Number of affected rows.
*/
public function delete($sql, array $bindings = array()) {
$this
->prepareStatement($sql)
->bindInputParameters($bindings)
->executePreparedStatement()
;
return $this->getStatement()->rowCount();
}
/**
* Prepare and validate an sql statement.
*
* ----------------------------------------------------
* If the database server cannot successfully prepare
* the statement, PDO::prepare() returns FALSE or emits
* PDOException (depending on error handling settings).
* ----------------------------------------------------
*
* @param string $sql Sql statement.
* @return $this
* @throws PDOException
* @throws UnexpectedValueException
*/
private function prepareStatement($sql) {
$this->connect();
try {
$statement = $this->getConnection()->prepare($sql);
if (!$statement) {
throw new UnexpectedValueException('The sql statement can not be prepared!');
}
$this->setStatement($statement);
} catch (PDOException $pdoException) {
echo $pdoException->getMessage();
exit();
} catch (Exception $exception) {
echo $exception->getMessage();
exit();
}
return $this;
}
/**
* Bind the input parameters to a prepared PDO statement.
*
* @param array $bindings Input parameters.
* @return $this
* @throws UnexpectedValueException
*/
private function bindInputParameters($bindings) {
foreach ($bindings as $key => $value) {
try {
$bound = $this->getStatement()->bindValue(
$this->getInputParameterName($key)
, $value
, $this->getInputParameterDataType($value)
);
if (!$bound) {
throw new UnexpectedValueException('A value can not be bound!');
}
} catch (Exception $exception) {
echo $exception->getMessage();
exit();
}
}
return $this;
}
/**
* Get the name of an input parameter by its key in the bindings array.
*
* @param int|string $key The key of the input parameter in the bindings array.
* @return int|string The name of the input parameter.
*/
private function getInputParameterName($key) {
return is_int($key) ? ($key + 1) : (':' . ltrim($key, ':'));
}
/**
* Get the PDO::PARAM_* constant, e.g the data type of an input parameter, by its value.
*
* @param mixed $value Value of the input parameter.
* @return int The PDO::PARAM_* constant.
*/
private function getInputParameterDataType($value) {
$dataType = PDO::PARAM_STR;
if (is_int($value)) {
$dataType = PDO::PARAM_INT;
} elseif (is_bool($value)) {
$dataType = PDO::PARAM_BOOL;
}
return $dataType;
}
/**
* Execute a prepared PDO statement.
*
* @return $this
* @throws UnexpectedValueException
*/
private function executePreparedStatement() {
try {
if (!$this->getStatement()->execute()) {
throw new UnexpectedValueException('The statement can not be executed!');
}
} catch (Exception $exception) {
echo $exception->getMessage();
exit();
}
return $this;
}
/**
* Get the ID of the last inserted row or of the sequence value.
*
* @param string $sequenceObjectName [optional] Name of the sequence object
* from which the ID should be returned.
* @return string The ID of the last row, or the last value retrieved from the specified
* sequence object, or an error IM001 SQLSTATE If the PDO driver does not support this.
* @throws PDOException
*/
public function getLastInsertId($sequenceObjectName = NULL) {
$this->connect();
try {
return $this->getConnection()->lastInsertId($sequenceObjectName);
} catch (PDOException $pdoException) {
echo $pdoException->getMessage();
exit();
}
}
/**
* Get connection configs.
*
* @return array
*/
public function getConnectionConfigs() {
return $this->connectionConfigs;
}
/**
* Set connection configs.
*
* @param array $connectionConfigs Connection configs.
* @return $this
*/
public function setConnectionConfigs($connectionConfigs) {
$this->connectionConfigs = $connectionConfigs;
return $this;
}
/**
* Get database connection.
*
* @return PDO Database connection.
*/
public function getConnection() {
return $this->connection;
}
/**
* Set database connection.
*
* @param PDO $connection Database connection.
* @return $this
*/
public function setConnection(PDO $connection) {
$this->connection = $connection;
return $this;
}
/**
* Get PDO statement.
*
* @return PDOStatement
*/
public function getStatement() {
return $this->statement;
}
/**
* Set PDO statement.
*
* @param PDOStatement $statement PDO statement.
* @return $this
*/
public function setStatement(PDOStatement $statement) {
$this->statement = $statement;
return $this;
}
}
这篇关于在一个响应中返回多个响应数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!