这个连接语句有什么问题?
What is wrong with this concatenate statement?
我正在使用 MySQL 服务器 Server version: 5.6.42-cll-lve - MySQL Community Server (GPL)
,我在使用 CONCAT()
时遇到了一些重大问题
public function get_urls() {
// Create query
$query = "SELECT a.Name, a.PrimaryVersion, e1.URL
FROM " . $this->table . " a
INNER JOIN
FunnelsFlows b ON a.Funnel_ID = b.Funnel_ID
INNER JOIN
BackendFlows c ON b.BackendFlow_ID = c.BackendFlow_ID
INNER JOIN
BackendLevels d ON CONCAT(c.Level, :lv) = d.BackendLevel_ID
LEFT JOIN
BackendPages e1 ON d.Upsell = e1.BackendPage_ID
LEFT JOIN
BackendPages e2 ON d.Downsell1 = e2.BackendPage_ID
LEFT JOIN
BackendPages e3 ON d.Downsell2 = e3.BackendPage_ID
WHERE
a.Funnel_ID = :fid
LIMIT 0,1";
// Prepare statement
$stmt = $this->conn->prepare($query);
// Bind ID
$stmt->bindParam(':fid', $this->fid, PDO::PARAM_INT);
$stmt->bindValue(':lv', $this->lv, PDO::PARAM_STR);
// Execute query
$stmt->execute();
运行 此代码引发以下错误:PHP Fatal error: Uncaught PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'c.Level' in 'on clause' in ...
您可以在此处查看整个数据库结构:
https://app.sqldbm.com/MySQL/Share/wBAF2JMRFFSoPPjIPdYZc0GFrngIE8md_DYjF4jNYw0
删除引号(列名和值):
CONCAT(a.Level, :level)
此外,您使用了错误的参数名称:
$stmt->bindParam(':level', $this->lv, PDO::PARAM_INT);
// ^^^^^
这个呢?
$query = "SELECT a.Name, b.URL
FROM " . $this->table . " a
INNER JOIN
FunnelsFlows b ON CONCAT(a.Level, ':lv') = b.Level_ID
WHERE
a.Funnel_ID = :fid
LIMIT 0,1";
// Prepare statement
$stmt = $this->conn->prepare($query);
// Bind ID
$stmt->bindParam(':fid', $this->fid, PDO::PARAM_INT);
$stmt->bindParam(':lv', $this->lv, PDO::PARAM_INT);
// Execute query
$stmt->execute();
回复很快,我现在就来解释一下。
我看到您想要将 table 列与字符串连接起来,对吗?
首先你有一个错误的 ident :level
,你试图用下面的语句 $stmt->bindParam(':lv', $this->lv, PDO::PARAM_INT);
绑定它所以你必须用 :lv
改变它或者将绑定语句更改为 $stmt->bindParam(':level', $this->lv, PDO::PARAM_INT);
.
第二 - 当你试图连接一个列时你必须删除引号所以它应该是 CONCAT('a.Level',
并且如果第二个运算符是一个字符串它应该在单引号中,所以完整的 CONCAT 运算符应该写成如下 CONCAT(a.Level, ':lv')
您的查询不能那样工作。您正在尝试使用参数 :lv
连接字段内容 CONCAT(c.Level, :lv)
。如果有列 Level
,这将生成一个字符串。但是,您宁愿构建一个动态列名,如 Level1
/ Level2
aso.
不幸的是,这不能通过参数来完成。这是因为查询计划已准备就绪。在执行时更改列名会改变查询计划。
在这种情况下,您要么需要构建动态 SQL,要么编写一个复杂的 ON
子句。
ON
子句:
ON
(
(:lv = 1 AND c.Level1 = d.BackendLevel_ID)
OR
(:lv = 2 AND c.Level2 = d.BackendLevel_ID)
-- and so on
)
动态SQL:
$sql = 'ON (c.Level' . inval($this->lv) . ' = d.BackendLevel_ID)'
既然PHP的intval
函数被认为是安全的,为了提高SQL性能,我更喜欢后一个例子。
我正在使用 MySQL 服务器 Server version: 5.6.42-cll-lve - MySQL Community Server (GPL)
,我在使用 CONCAT()
public function get_urls() {
// Create query
$query = "SELECT a.Name, a.PrimaryVersion, e1.URL
FROM " . $this->table . " a
INNER JOIN
FunnelsFlows b ON a.Funnel_ID = b.Funnel_ID
INNER JOIN
BackendFlows c ON b.BackendFlow_ID = c.BackendFlow_ID
INNER JOIN
BackendLevels d ON CONCAT(c.Level, :lv) = d.BackendLevel_ID
LEFT JOIN
BackendPages e1 ON d.Upsell = e1.BackendPage_ID
LEFT JOIN
BackendPages e2 ON d.Downsell1 = e2.BackendPage_ID
LEFT JOIN
BackendPages e3 ON d.Downsell2 = e3.BackendPage_ID
WHERE
a.Funnel_ID = :fid
LIMIT 0,1";
// Prepare statement
$stmt = $this->conn->prepare($query);
// Bind ID
$stmt->bindParam(':fid', $this->fid, PDO::PARAM_INT);
$stmt->bindValue(':lv', $this->lv, PDO::PARAM_STR);
// Execute query
$stmt->execute();
运行 此代码引发以下错误:PHP Fatal error: Uncaught PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'c.Level' in 'on clause' in ...
您可以在此处查看整个数据库结构:
https://app.sqldbm.com/MySQL/Share/wBAF2JMRFFSoPPjIPdYZc0GFrngIE8md_DYjF4jNYw0
删除引号(列名和值):
CONCAT(a.Level, :level)
此外,您使用了错误的参数名称:
$stmt->bindParam(':level', $this->lv, PDO::PARAM_INT);
// ^^^^^
这个呢?
$query = "SELECT a.Name, b.URL
FROM " . $this->table . " a
INNER JOIN
FunnelsFlows b ON CONCAT(a.Level, ':lv') = b.Level_ID
WHERE
a.Funnel_ID = :fid
LIMIT 0,1";
// Prepare statement
$stmt = $this->conn->prepare($query);
// Bind ID
$stmt->bindParam(':fid', $this->fid, PDO::PARAM_INT);
$stmt->bindParam(':lv', $this->lv, PDO::PARAM_INT);
// Execute query
$stmt->execute();
回复很快,我现在就来解释一下。
我看到您想要将 table 列与字符串连接起来,对吗?
首先你有一个错误的 ident :level
,你试图用下面的语句 $stmt->bindParam(':lv', $this->lv, PDO::PARAM_INT);
绑定它所以你必须用 :lv
改变它或者将绑定语句更改为 $stmt->bindParam(':level', $this->lv, PDO::PARAM_INT);
.
第二 - 当你试图连接一个列时你必须删除引号所以它应该是 CONCAT('a.Level',
并且如果第二个运算符是一个字符串它应该在单引号中,所以完整的 CONCAT 运算符应该写成如下 CONCAT(a.Level, ':lv')
您的查询不能那样工作。您正在尝试使用参数 :lv
连接字段内容 CONCAT(c.Level, :lv)
。如果有列 Level
,这将生成一个字符串。但是,您宁愿构建一个动态列名,如 Level1
/ Level2
aso.
不幸的是,这不能通过参数来完成。这是因为查询计划已准备就绪。在执行时更改列名会改变查询计划。
在这种情况下,您要么需要构建动态 SQL,要么编写一个复杂的 ON
子句。
ON
子句:
ON
(
(:lv = 1 AND c.Level1 = d.BackendLevel_ID)
OR
(:lv = 2 AND c.Level2 = d.BackendLevel_ID)
-- and so on
)
动态SQL:
$sql = 'ON (c.Level' . inval($this->lv) . ' = d.BackendLevel_ID)'
既然PHP的intval
函数被认为是安全的,为了提高SQL性能,我更喜欢后一个例子。