【问题标题】:MySQL inner join two columns on one columnMySQL内部连接一列上的两列
【发布时间】:2012-04-26 20:19:29
【问题描述】:

我被困在我的表的内部连接方案中。你能帮我么?我在这里做错了什么?

这是我正在尝试做的场景:

我有帐单和运输国家/州列,我试图用内部连接填充它们,但不知何故它不起作用。非常感谢您的帮助:

 $sql = $this->connection->query("SELECT * FROM ".TBL_USERS." 
    INNER JOIN ".TBL_USER_LEVEL." ON ".TBL_USERS.".userlevel = ".TBL_USER_LEVEL.".user_level_id 
    INNER JOIN ".TBL_COUNTRIES." ON ".TBL_USERS.".country OR ".TBL_USERS.".bcountry = ".TBL_COUNTRIES.".country_id
    INNER JOIN ".TBL_STATES." ON ".TBL_USERS.".states OR ".TBL_USERS.".bstates  = ".TBL_STATES.".states_id
    WHERE ".TBL_USERS.".username = '$username'");

我将查询更改为;我刚开始的错误是

PHP 致命错误:未捕获的异常 'PDOException' 带有消息 'SQLSTATE[42000]:语法错误或访问冲突:1066 Not unique table/alias: 'countries'' in

 $sql = $this->connection->query("SELECT * FROM ".TBL_USERS." 
    INNER JOIN ".TBL_USER_LEVEL." ON ".TBL_USERS.".userlevel = ".TBL_USER_LEVEL.".user_level_id 
    INNER JOIN ".TBL_COUNTRIES." ON ".TBL_USERS.".country = ".TBL_COUNTRIES.".country_id
    INNER JOIN ".TBL_COUNTRIES." ON ".TBL_USERS.".bcountry = ".TBL_COUNTRIES.".country_id
    INNER JOIN ".TBL_STATES." ON ".TBL_USERS.".states = ".TBL_STATES.".states_id

    INNER JOIN ".TBL_STATES." ON ".TBL_USERS.".bstates = ".TBL_STATES.".states_id

    WHERE ".TBL_USERS.".username = '$username'");

这里的语法正确,非常感谢@Tiberiu-Ionuț Stan

$sql = $this->connection->query("SELECT * FROM ".TBL_USERS." 
    LEFT JOIN ".TBL_COUNTRIES." ON ".TBL_USERS.".country = ".TBL_COUNTRIES.".country_id 

   LEFT JOIN ".TBL_COUNTRIES." AS ".TBL_COUNTRIES."_b ON ".TBL_USERS.".bcountry=".TBL_COUNTRIES."_b.country_id

    INNER JOIN ".TBL_USER_LEVEL." ON ".TBL_USERS.".userlevel = ".TBL_USER_LEVEL.".user_level_id 
    LEFT JOIN ".TBL_STATES." ON ".TBL_USERS.".states = ".TBL_STATES.".states_id 

    LEFT JOIN ".TBL_STATES." AS ".TBL_STATES."_b ON ".TBL_USERS.".bstates=".TBL_STATES."_b.states_id


    WHERE ".TBL_USERS.".username = '$username'");

【问题讨论】:

  • 您是否收到 SQL 错误?如果是这样,你可以发布它吗?乍一看,我认为您不能在 JOIN 子句中使用 OR - 没有多大意义。无论如何都无法在 MySQL 文档中看到。

标签: php mysql inner-join


【解决方案1】:

您可以在连接语句中使用 OR 和 AND。 我一直都这样做。 这是一个有效的方法:

  LEFT JOIN `currencies` ON (
   `currency_foreign`=`invoice_entry_amount_currency`
   AND
   `currency_reference`='".$strTransformToCurrency."'
   AND
   `currency_date`=FLOOR(`invoice_paid_timestamp`/86400)*86400
  )

问题就在这里:

   INNER JOIN ".TBL_COUNTRIES." ON ".TBL_USERS.".country = ".TBL_COUNTRIES.".country_id
   INNER JOIN ".TBL_COUNTRIES." ON ".TBL_USERS.".bcountry = ".TBL_COUNTRIES.".country_id

MySQL 无法决定加入国家表的关系(因为 MySQL 认为 .country 和 .countryb 可能不同 - 所以加入后它不知道哪些列将被返回或用于条件和排序)。

试试这样:

  INNER JOIN ".TBL_COUNTRIES." ON ".TBL_USERS.".country = ".TBL_COUNTRIES.".country_id
  INNER JOIN ".TBL_COUNTRIES." AS ".TBL_COUNTRIES."_b ON ".TBL_USERS.".bcountry=".TBL_COUNTRIES."_b.country_id

如果您有非常大的表,请使用包含条件和顺序的完整最终查询执行 EXPLAIN,以了解 MySQL 是否因为“TBL_USERS AS TBL_USERS_B”而进行表复制。

【讨论】:

  • 我遇到了同样的错误:PHP 致命错误:未捕获的异常 'PDOException' 带有消息 'SQLSTATE[42000]:语法错误或访问冲突:1066 不是唯一的表/别名:'国家''
  • 对 TBL_STATES 做同样的事情 ;)
  • 为 TBL_STATES 添加一个别名,就像我向您展示的那样在 TBL_COUNTRIES 上。
  • 非常感谢您的帮助,我不再收到错误消息,但是现在所有字段都为空,我无法填充任何数据:) 我想哭:)
  • 我在那个 JOIN 中犯了一个错误。在表达式部分也将 _b 添加到 TBL_COUNTRIES (".TBL_USERS.".bcountry=".TBL_COUNTRIES."_b.country_id)。对 TBL_STATES/ 执行相同的操作
【解决方案2】:

您不能使用像JOIN table ON field OR another_field = expression 这样的结构,除非引用的field 是布尔类型。

您应该使用将返回布尔结果的构造,在您的情况下是这样的:

$sql = $this->connection->query("SELECT * FROM $TBL_USERS 
    JOIN $TBL_USER_LEVEL ON $TBL_USERS.userlevel = $TBL_USER_LEVEL.user_level_id 
    JOIN $TBL_COUNTRIES ON $TBL_USERS.country = $TBL_COUNTRIES.country_id
      OR $TBL_USERS.bcountry = $TBL_COUNTRIES.country_id
    JOIN $TBL_STATES ON $TBL_USERS.states = $TBL_STATES.states_id
      OR $TBL_USERS.bstates  = $TBL_STATES.states_id
    WHERE $TBL_USERS.username = '$username'");

我也直接使用了变量,否则很多字符串连接看起来很乱。 您的查询现在对SQLi 开放。

【讨论】:

  • 只有当各个变量可以使用输入参数(例如 argv、$_GET 等)以某种方式直接或间接写入时,该查询才对 SQL 注入开放。
  • 顺便说一句,这些不是变量,它们是常量,因此它们不太可能从请求参数中获取任何值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-07
  • 2014-06-02
  • 2016-07-02
  • 1970-01-01
相关资源
最近更新 更多