我构建了一个SQL查询来提供股票持有的摘要,即使用PHP,PDO,MySQL对给定股票的所有股票交易进行分组。在测试PHPMyAdmin时,SQL工作正常(通过将命名参数从:c_code更改为c.code,:交换到" LSE",:p_portfolio_id到p.portfolio_id)
我不确定如何在这种情况下构造bindParam语句,或者如果我必须在查询中使用JOIN语句。我比较新,但学习速度很快,非常感谢任何帮助,Cheers Colin在这里是代码。
更改了代码返回没有错误但没有记录..
<?php
include('db.php');
include('function.php');
$query = '';
$output = array();
$query .= "SELECT
t.user_id AS tuser_id,
p.user_id AS puser_id,
t.exchange AS exchange,
t.code AS code,
c.name AS name,
p.name AS portfolio,
CEILING(c.price * t.quantity / 100) AS value,
DATE_FORMAT(t.trade_date,'%d%m%y') AS trade_date,
t.type AS type,
SUM(t.quantity) AS quantity,
t.price AS price,
SUM(t.commission) AS commission,
SUM(t.total_cost) AS total_cost
FROM
transaction t, company c, portfolio p
WHERE
t.code = :c_code
AND
t.exchange = :t_exchange
AND
t.portfolio_id = :p_portfolio_id
GROUP BY
t.code
ORDER BY
t.code ";
if(isset($_POST["search"]["value"]))
{
$query .= 'AND trade_date LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR exchange LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR code LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR type LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR quantity LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR price LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR commission LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR total_cost LIKE "%'.$_POST["search"]["value"].'%" ';
}
if(isset($_POST["order"]))
{
$query .= 'ORDER BY '.$_POST['order']['0']['column'].' '.$_POST['order']['0']['dir'].' ';
}
else
{
$query .= 'ORDER BY id DESC ';
}
if($_POST["length"] != -1)
{
$query .= 'LIMIT ' . $_POST['start'] . ', ' . $_POST['length'];
}
$exchange = "LSE";
$statement = $connection->prepare($query);
$statement->bindParam(':t_exchange', $exchange, PDO::PARAM_STR);
$statement->bindParam(':c_code', $_POST['company.code'], PDO::PARAM_STR);
$statement->bindParam(':p_portfolio_id', $_POST['portfolio.id'], PDO::PARAM_STR);
$statement->execute();
$result = $statement->fetchAll();
$data = array();
$filtered_rows = $statement->rowCount();
foreach($result as $row)
{
$sub_array = array();
$sub_array[] = $row["trade_date"];
$sub_array[] = $row["exchange"];
$sub_array[] = $row["code"];
$sub_array[] = $row["type"];
$sub_array[] = $row["quantity"];
$sub_array[] = $row["price"];
$sub_array[] = $row["commission"];
$sub_array[] = $row["total_cost"];
$sub_array[] = '<button type="button" name="update" id="'.$row["id"].'" class="btn btn-warning btn-xs update">Update</button>';
$sub_array[] = '<button type="button" name="delete" id="'.$row["id"].'" class="btn btn-danger btn-xs delete">Delete</button>';
$data[] = $sub_array;
}
$output = array(
"draw" => intval($_POST["draw"]),
"recordsTotal" => $filtered_rows,
"recordsFiltered" => get_total_all_records(),
"data" => $data
);
echo json_encode($output);
?>
下面的SQL在PHPMyAdmin中运行SQL工作正常
SELECT
t.user_id AS tuser_id,
p.user_id AS puser_id,
t.exchange AS exchange,
t.code AS code,
c.name AS name,
p.name AS portfolio,
CEILING(c.price * t.quantity / 100) AS value,
DATE_FORMAT(t.trade_date,'%d%m%y') AS trade_date,
t.type AS type,
SUM(t.quantity) AS quantity,
t.price AS price,
SUM(t.commission) AS commission,
SUM(t.total_cost) AS total_cost
FROM
transaction t, company c, portfolio p
WHERE
t.code = c.code
AND
t.exchange = "LSE"
AND
t.portfolio_id = p.id
GROUP BY
t.code
ORDER BY
t.code
我试图通过调用holdg_home.php中的holdg_fetch.php来集成一些推荐的代码,以便在表格中显示MySQL数据,但是我收到错误 &#34; DataTables警告:table id = transaction_data - 无效的JSON响应。 有关此错误的详细信息,请参阅http://datatables.net/tn/1 &#34; 我可以成功运行holdg_fetch.php,没有错误。我可以成功运行holdg_home.php调用trans_fetch.php,没有错误。
注意:一旦修复此JSON错误,我将从您的建议中挑选出安全性和结构。非常感谢Colin
trans_fetch.php
<?php
include('db.php');
include('function.php');
$query = '';
$output = array();
$query .= "
SELECT
*,
DATE_FORMAT(trade_date,'%d%m%y') AS trade_date
FROM
transaction ";
if(isset($_POST["search"]["value"]))
{
$query .= 'WHERE trade_date LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR exchange LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR code LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR type LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR quantity LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR price LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR commission LIKE "%'.$_POST["search"]["value"].'%" ';
$query .= 'OR total_cost LIKE "%'.$_POST["search"]["value"].'%" ';
}
if(isset($_POST["order"]))
{
$query .= 'ORDER BY '.$_POST['order']['0']['column'].' '.$_POST['order']['0']['dir'].' ';
}
else
{
$query .= 'ORDER BY id DESC ';
}
if($_POST["length"] != -1)
{
$query .= 'LIMIT ' . $_POST['start'] . ', ' . $_POST['length'];
}
$statement = $connection->prepare($query);
$statement->execute();
$result = $statement->fetchAll();
$data = array();
$filtered_rows = $statement->rowCount();
foreach($result as $row)
{
$sub_array = array();
$sub_array[] = $row["trade_date"];
$sub_array[] = $row["exchange"];
$sub_array[] = $row["code"];
$sub_array[] = $row["type"];
$sub_array[] = $row["quantity"];
$sub_array[] = $row["price"];
$sub_array[] = $row["commission"];
$sub_array[] = $row["total_cost"];
$sub_array[] = '<button type="button" name="update" id="'.$row["id"].'" class="btn btn-warning btn-xs update">Update</button>';
$sub_array[] = '<button type="button" name="delete" id="'.$row["id"].'" class="btn btn-danger btn-xs delete">Delete</button>';
$data[] = $sub_array;
}
$output = array(
"draw" => intval($_POST["draw"]),
"recordsTotal" => $filtered_rows,
"recordsFiltered" => get_total_all_records(),
"data" => $data
);
echo json_encode($output);
?>
holdg_home.php
<?php include 'db.php'; ?>
<?php include("header-nav2.php"); ?>
<main>
<div class="container box">
<br />
<div class="table-responsive">
<br />
<div align="right">
<button type="button" id="add_button" data-toggle="modal" data-target="#transactionModal" class="btn btn-warning"><i class="fa fa-plus" aria-hidden="true"></i></button>
</div>
<br />
<table id="transaction_data" class="table table-bordered table-striped">
<thead class="blue-grey lighten-4">
<tr>
<th width="11%">TradeDate</th>
<th width="11%">Exchange</th>
<th width="11%">Code</th>
<th width="11%">Type</th>
<th width="11%">Quantity</th>
<th width="11%">Price</th>
<th width="11%">Commission</th>
<th width="11%">TotalCost</th>
<th width="6%">Edit</th>
<th width="6%">Delete</th>
</tr>
</thead>
</table>
</div>
</div>
<?php include("footer.php"); ?>
</body>
</html>
<script type="text/javascript" language="javascript" >
$(document).ready(function(){
$('#add_button').click(function(){
$('#transaction_form')[0].reset();
$('.modal-title').text("Add Transaction");
$('#action').val("Add");
$('#operation').val("Add");
});
var dataTable = $('#transaction_data').DataTable({
"processing":true,
"serverSide":true,
"order":[],
"ajax":{
url:"holdg_fetch.php",
type:"POST"
},
"columnDefs":[
{//removes sort from columns given by targets, where 0 - remove Column 1 sort etc.
"targets":[8, 9],
"orderable":false,
},
],
});
...
holdg_fetch.php
<?php
include('db.php');
include('function.php');
$query = '';
$output = array();
$query .= "
SELECT
t.user_id AS tuser_id,
p.user_id AS puser_id,
t.exchange AS exchange,
t.code AS code,
c.name AS name,
p.name AS portfolio,
CEILING(c.price * t.quantity / 100) AS value,
DATE_FORMAT(t.trade_date,'%d%m%y') AS trade_date,
t.type AS type,
SUM(t.quantity) AS quantity,
t.price AS price,
SUM(t.commission) AS commission,
SUM(t.total_cost) AS total_cost
FROM
transaction t
inner join company c on (t.code=c.code)
inner join portfolio p on (t.portfolio_id = p.id)
GROUP BY
t.code";
// WHERE
// 1=1
//if(isset($_POST["search"]["value"]))
//{
// $query .= ' WHERE trade_date LIKE "%'.$_POST["search"]["value"].'%" ';
// $query .= 'OR exchange LIKE "%'.$_POST["search"]["value"].'%" ';
// $query .= 'OR code LIKE "%'.$_POST["search"]["value"].'%" ';
// $query .= 'OR type LIKE "%'.$_POST["search"]["value"].'%" ';
// $query .= 'OR quantity LIKE "%'.$_POST["search"]["value"].'%" ';
// $query .= 'OR price LIKE "%'.$_POST["search"]["value"].'%" ';
// $query .= 'OR commission LIKE "%'.$_POST["search"]["value"].'%" ';
// $query .= 'OR total_cost LIKE "%'.$_POST["search"]["value"].'%" ';
//}
//if(isset($_POST["order"]))
//{
// $query .= 'ORDER BY '.$_POST['order']['0']['column'].' '.$_POST['order']['0']['dir'].' ';
//}
//else
//{
// $query .= 'ORDER BY id DESC ';
//}
//if($_POST["length"] != -1)
//{
// $query .= ' LIMIT ' . $_POST['start'] . ', ' . $_POST['length'];
//}
//$query .= ' GROUP BY t.code';
$statement = $connection->prepare($query);
$statement->execute();
$result = $statement->fetchAll();
var_dump($result);
$data = array();
$filtered_rows = $statement->rowCount();
foreach($result as $row)
{
$sub_array = array();
$sub_array[] = $row["trade_date"];
$sub_array[] = $row["exchange"];
$sub_array[] = $row["code"];
$sub_array[] = $row["type"];
$sub_array[] = $row["quantity"];
$sub_array[] = $row["price"];
$sub_array[] = $row["commission"];
$sub_array[] = $row["total_cost"];
// $sub_array[] = '<button type="button" name="update" id="'.$row["id"].'" class="btn btn-warning btn-xs update">Update</button>';
// $sub_array[] = '<button type="button" name="delete" id="'.$row["id"].'" class="btn btn-danger btn-xs delete">Delete</button>';
$data[] = $sub_array;
}
$output = array(
// "draw" => intval($_POST["draw"]),
//"recordsTotal" => $filtered_rows,
//"recordsFiltered" => get_total_all_records(),
"data" => $data
);
echo json_encode($output);
?>
我现在修复了JSON错误,数据和选定列不匹配,请忽略上面的错误,现在已修复
答案 0 :(得分:1)
在我看来,动态生成的SQL存在问题。
GROUP BY
t.code
ORDER BY
t.code AND trade_date LIKE "%foo%" OR exchange LIKE "%foo%"
可能MySQL会接受语法,并允许处理查询。但是这些条件不是WHERE子句中的谓词。 ORDER BY之后的整行将被评估为单个布尔表达式,它将为每一行返回0,1或NULL。 ORDER BY将对布尔值进行操作。 (这是一个聪明的伎俩,一个方便的捷径,但我怀疑这里的代码并不意味着实现。)
如果我们想要为WHERE子句添加条件,那么需要在 GROUP BY之前。但是在WHERE子句中,我们不能引用SELECT列表中指定的别名。 (我们可以在HAVING条款中。)
请注意,AND
的优先顺序高于OR
。
a AND b OR c
与 (a AND b) OR c
相同而不是 a AND (b OR c)
向查询添加另一个ORDER BY绝对不是有效的SQL。像这样的结构,在语句末尾有两个ORDER BY子句
GROUP BY
t.code
ORDER BY
t.code ORDER BY whatever
将导致SQL语法错误。
问:如果我必须在查询中使用JOIN语句?
查询已指定JOIN操作。逗号是JOIN操作的有效语法。这样:
FROM
transaction t, company c, portfolio p
WHERE
t.code = c.code
AND
t.exchange = 'LSE'
AND
t.portfolio_id = p.id
是老式的写作我们现在写的东西:
FROM transaction t
JOIN company c
ON c.code = t.code
JOIN portfolio p
ON p.id = t.portfolio_id
WHERE t.exchange = :t_exchange
请注意,我们只需要一个绑定占位符就可以将值绑定到那里。我们无法通过绑定占位符提供标识符(如列名)或其他SQL语法。
鉴于我们的绑定占位符是输入,我们可以使用bindValue
代替bindParam
。
$sth = $conn->prepare($sql);
$sth->bindValue(':t_exchange', $exchange, PDO::PARAM_STR);
查询中提供的其他值也应添加为绑定占位符。 从不将可能不安全的值合并到SQL文本中。
我认为(没有规范,我只是在这里猜测)我们打算生成一个如下所示的查询:
FROM transaction t
JOIN company c
ON c.code = t.code
JOIN portfolio p
ON p.id = t.portfolio_id
WHERE 1=1
AND ( t.trade_date LIKE CONCAT('%', :search_01 , '%')
OR t.exchange LIKE CONCAT('%', :search_02 , '%')
OR t.code LIKE CONCAT('%', :search_03 , '%')
OR t.type LIKE CONCAT('%', :search_04 , '%')
)
GROUP BY ...
ORDER BY ...
(我在字符串文字周围使用了SQL标准单引号。只要sql_mode不包含ANSI_QUOTES,MySQL就允许我们用双引号代替单引号。)
$sth = $conn->prepare($sql);
$sth->bindValue(':search_01', $_POST["search"]["value"], PDO::PARAM_STR);
$sth->bindValue(':search_02', $_POST["search"]["value"], PDO::PARAM_STR);
$sth->bindValue(':search_03', $_POST["search"]["value"], PDO::PARAM_STR);
$sth->bindValue(':search_04', $_POST["search"]["value"], PDO::PARAM_STR);
(我将假设$_POST["search"]
是一个数组,我们知道我们在这里做了什么,从数组中获取一个值。)
如果我们有条件地附加LIMIT条款......
if( someconditition ) {
$sql .= " LIMIT :nskip, :nrows";
}
然后,当我们绑定参数值时,我们需要确定是否添加了LIMIT子句。检查相同的条件将是方便的(只要我们知道在我们做好准备之后,条件将在稍后评估相同的情况。)
if( somecondition ) {
$sth->bindValue(':nskip', (int)$_POST["start"] , PDO::PARAM_INT);
$sth->bindValue(':nrows', (int)$_POST["length"], PDO::PARAM_INT);
}
从不将可能不安全的值合并到SQL语句的文本中。
小鲍比表(对妈妈的利用)https://xkcd.com/327/
答案 1 :(得分:0)
此代码存在一些问题:
在添加更多where子句之前,在代码顶部的查询中按顺序排序依据(在if块中) - 这将导致错误。
将like子句构造为字符串 - 您对SQL注入攻击持开放态度。您可以将like子句绑定为参数:
$query .= 'where trade_date like :trade_date';
//then bind it
$statement->bindParam( ':trade_date', '%' . $_POST['search']['value'] .
'%', PDO::PARAM_STR );
看起来您需要围绕搜索字词的where子句使用括号。
通过代码预先定义订单并使用某种参数来创建您的查询 - 不要相信用户输入 - 您将被黑客攻击。
使用显式联接 - 我想我已经在下面的代码中将它们更正了。
使用绑定参数构造limit子句。
$query .= "LIMIT :limitstart,:limitlength";
$statement->bindValue(':limitstart', (int) trim( $_POST['start'] ), PDO::PARAM_INT );
$statement->bindValue(':limitlength', (int) trim( $_POST['length'] ), PDO::PARAM_INT );
尝试此代码 - 调试除了执行查询,因为我没有你的数据库。
<?php
include('db.php');
include('function.php');
$searchFields = array( 'exchange', 'code','type','quantity', 'price', 'commission','total_cost' );
$output = array();
// i'm guessing at the join for portfolio below.
// i'm guessing that the portfolioid where clause needs to be removed because it was probably used only for joins
// where 1=1 will be optimized out by the query optimizer
$query = "SELECT
t.user_id AS tuser_id,
p.user_id AS puser_id,
t.exchange AS exchange,
t.code AS code,
c.name AS name,
p.name AS portfolio,
CEILING(c.price * t.quantity / 100) AS value,
DATE_FORMAT(t.trade_date,'%d%m%y') AS trade_date,
t.type AS type,
SUM(t.quantity) AS quantity,
t.price AS price,
SUM(t.commission) AS commission,
SUM(t.total_cost) AS total_cost
FROM
transaction t
inner join company c on (t.code=c.code)
inner join portfolio p on (t.portfolio_id = p.id)
WHERE
1=1
";
$bindSearch = false;
$searchValue = '';
if( array_key_exists( 'search', $_POST ) && array_key_exists( 'value', $_POST['search'] ) && ! empty( $_POST['search']['value'] ) )
{
$bindSearch = true;
$searchValue = $_POST['search']['value'];
// 1=1 will be optimized out
$query .= "\tAND (\n\t\t1=1\n";
foreach( $searchFields as $field )
{
$query .= "\t\tOR $field LIKE : $field\n";
}
$query .= "\t)\n";
}
if( array_key_exists( 'order', $_POST ) && ! empty( $_POST['order'] ) )
{
switch ( $_POST['order']['0']['column'] )
{
case 'code':
$query .= 'ORDER BY code ';
break;
default:
$query .= 'ORDER BY id DESC ';
break;
}
}
$bindLimit = false;
if( array_key_exists( 'length', $_POST ) && $_POST['length'] > 0 )
{
$bindLimit = true;
$query .= "\n\tLIMIT :limitstart,:limitlength";
}
?>
<form method="POST">
search: <input type="text" name="search[value]"><br>
order: <input type="text" name="order[0][column]"><br>
Limit Start: <input type="text" name="start"><br>
Limit Length: <input type="text" name="length"><br>
<button type="submit">Submit</button>
</form>
<?
echo "<pre>$query";
$statement = $connection->prepare($query);
$exchange = "LSE";
$statement->bindParam( ':exchange', $exchange, PDO::PARAM_STR );
if( $bindSearch )
{
foreach( $searchFields as $field )
{
$statement->bindParam( ':' . $field, $searchValue , PDO::PARAM_STR );
}
}
if( $bindLimit )
{
$statement->bindValue(':limitstart', (int) trim( $_POST['start'] ), PDO::PARAM_INT );
$statement->bindValue(':limitlength', (int) trim( $_POST['length'] ), PDO::PARAM_INT );
}
$statement->execute();
$result = $statement->fetchAll();
print_r( $result );
var_dump( $result );
$data = array();
$filtered_rows = $statement->rowCount();
foreach($result as $row)
{
$sub_array = array();
$sub_array[] = $row["trade_date"];
$sub_array[] = $row["exchange"];
$sub_array[] = $row["code"];
$sub_array[] = $row["type"];
$sub_array[] = $row["quantity"];
$sub_array[] = $row["price"];
$sub_array[] = $row["commission"];
$sub_array[] = $row["total_cost"];
$sub_array[] = '<button type="button" name="update" id="'.$row["id"].'" class="btn btn-warning btn-xs update">Update</button>';
$sub_array[] = '<button type="button" name="delete" id="'.$row["id"].'" class="btn btn-danger btn-xs delete">Delete</button>';
$data[] = $sub_array;
}
$output = array(
"draw" => intval($_POST["draw"]),
"recordsTotal" => $filtered_rows,
"recordsFiltered" => get_total_all_records(),
"data" => $data
);
echo json_encode($output);
&GT;
这将生成以下查询:
SELECT
t.user_id AS tuser_id,
p.user_id AS puser_id,
t.exchange AS exchange,
t.code AS code,
c.name AS name,
p.name AS portfolio,
CEILING(c.price * t.quantity / 100) AS value,
DATE_FORMAT(t.trade_date,'%d%m%y') AS trade_date,
t.type AS type,
SUM(t.quantity) AS quantity,
t.price AS price,
SUM(t.commission) AS commission,
SUM(t.total_cost) AS total_cost
FROM
transaction t
inner join company c on (t.code=c.code)
inner join portfolio p on (t.portfolio_id = p.id)
WHERE
1=1
AND (
1=1
OR exchange LIKE : exchange
OR code LIKE : code
OR type LIKE : type
OR quantity LIKE : quantity
OR price LIKE : price
OR commission LIKE : commission
OR total_cost LIKE : total_cost
)
ORDER BY id DESC
答案 2 :(得分:-4)
这太长了你可以在其中创建一个程序,你必须通过程序调用所有参数。 过程对于该类型的查询是完全有用的,并且也是安全的。 如果你只想选择你必须创建一个视图就可以使用sqlyog来帮助你加入你可以在设计的帮助下创建你的连接