【问题标题】:Can nested arrays/join be done with Php::PDO?可以使用 Php::PDO 完成嵌套数组/连接吗?
【发布时间】:2014-07-22 07:52:50
【问题描述】:

我害怕我要求太多,但如果可能的话,我不想编写代码。 有一个“用户(ID,USERNAME)”和一个“图片(ID,USER_ID,NAME)”表。如果您想获取用户的图像,您只需使用:

SELECT * FROM users LEFT JOIN pictures ON pictures.USER_ID = users.ID;

但是返回一个简单的关联数组。我想看到这样的东西:

 ID => 1
 USERNAME => "user1";
 pictures => array();

 ID => 1
 USERNAME => "user2";
 pictures => array();

 ID => 1
 USERNAME => "user3";
 pictures => array(
    ID => 1
    USER_ID => 3
    NAME = "picture of user3"
 )

所以我想看一个嵌套的多维关联数组,我不知道我是否对 PDO 要求太多。我想我应该在某个地方为 PDO 设置外键。有任何想法吗?可以做到吗?我是 PDO 的新手

【问题讨论】:

  • 顺便说一句,所有的自动化 PDO 都可以在 fetchAll() 手册页中列出
  • 这与PDO 本身无关,外键不会使数据库的工作方式有所不同。获取多维结果集并不是 MySQL 的运作方式。只需准备一个SELECT * FROM pictures 语句,遍历用户,并获取相关数据(当然,正确的索引总是一个好主意)
  • 所以 SELECT * FROM users 和另一个 SELECT * FROM 循环内的图片?我会立即被解雇:)))))
  • @JohnSmith:不,我说:准备一份声明,而不是循环中的SELECT *$stmt2->execute(array(':userId' => $user->id)); $user->pictures = $stmt2->fetchAll(); $stmt2->closeCursor(); PS:SELECT * FROM users 足以在 99% 的情况下解雇某人跨度>
  • @EliasVanOotegem 从架构的角度来看,他的初始查询被认为更好。然而,循环内的简单条件将有助于过滤掉重复的名称并将图片组合在一起。

标签: php mysql sql arrays pdo


【解决方案1】:

简短的回答是否定的,它不能完成。但是,它与 PDO 无关。它与 MySQL 有关:MySQL 不是 PHP。它的工作是存储和获取数据。如果您JOIN 2 个或更多表并获取结果,那么数据库将很乐意这样做。
然后将“按原样”获取数据,也就是说:以几乎与存储数据相同的方式。如果您想要一个二维数组,这意味着数据存储在一个表中,该表包含本身就是表的字段。 MySQL 不这样做:它没有嵌套表(例如,MS SQL Server 可以通过将 XML 存储在字段中来做到这一点)。

然而,PHP 可以处理查询返回的数据,使用一个简单的循环:

$stmt = $pdo->query(
    'SELECT u.*, p.id as picture_id, p.name as picture_name
    FROM users u
    LEFT JOIN pictures p
      ON u.id = p.user_id
');
$endResult = array();
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
    if (!isset($endResult[$row['id']]))
        $endResult[$row['id']] = array(
            'id' => $row['id'],
            'username' => $row['username'],
            'pictures' => array();
        );
    $endResult[$row['id']]['pictures'][] = array(
        'id' => $row['picture_id'],
        'name' => $row['picture_name']
    );
}

真的是那么简单。您可能也知道:亲吻是最重要的。接下来的内容纯属学术性的。下面列出的代码不应使用,但我有点得意忘形,不“保留”查询似乎很可惜我的疯狂时刻产生了......所以我把它贴在这里


此代码不可使用。永远!

这样做可能会对您自己、您周围的人和整个人类造成严重和永久性的伤害。如果您是那种在阅读此答案的其余部分时可能会想“嘿,我可能会使用这个”的人,请不要再读了。并获得帮助。

当然,还有其他选择。例如,您可以通过按用户 ID 对结果集进行分组来减少获取的行数。如果你这样做,你必须GROUP_CONCATpictures 表中的值。我不建议这样做,因为它取代了逻辑:逻辑属于应用程序,而不是数据库服务器或查询,只要知道这是可能的:

SELECT u.*,
    GROUP_CONCAT(p.id) AS picture_ids,
    GROUP_CONCAT(p.name) AS picture_names
FROM users u
LEFT JOIN pictures p?
  ON u.id = p.user_id
GROUP BY u.id;

默认情况下,MySQL 将使用逗号作为分隔符连接pictures 表中的值。在这种情况下,只需 explode-ing 将结果放入数组中即可:

$results = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
    $pictures = array();
    $ids = explode(',', $row['picture_ids']);
    $names = explode(',', $row['picture_names']);
    foreach ($ids as $k => $id)
    {
        $pictures[] = array(
            'id' => $id,
            'name' => $names[$k]
        );
    }
    $results[] = array(
        'id' => $row['id'],
        'username' => $row['username'],
        'pictures' => $pictures
    );
}

当然,如果图片名称包含逗号,上面的代码将完全失败,因此最好更改GROUP_CONCAT使用的分隔符:

GROUP_CONCAT(p.name, '@#@#@')

或者,REPLACE 带有分号的逗号:

GROUP_CONCAT(REPLACE(p.name, ',', ';'))

但由于我们要深入挖掘:一分钱,一英镑,您不妨编写一个查询,选择pictures 数据作为json 编码字符串。我们需要为此做些什么?简单:

  • CONCAT 将数据转换成类似[{"id":%d, "name":"%s"]} 的字符串格式,其中 %d 是一个 int,%s 是图片的名称。
  • 我们还必须确保图片名称中不包含",因为这会导致 JSON 格式错误。添加转义 \ 很危险,因为这样的反斜杠可能已经存在。
  • 获取数据,然后json_decodepictures 数据。

对于如此简单的任务,生成的查询非常复杂,但它是:

SELECT u.*,
  CONCAT(
    '[',
    GROUP_CONCAT(
      CONCAT(
        '{"id":',
        p.id,
        ',"name":"',
        REPLACE(
          p.name,
          '"',
          '"'
        ),
        '"}'
      )
    ),
    ']'
) AS pictures
FROM users u
LEFT JOIN pictures p
  ON u.id = p.user_id
GROUP_BY u.id;

在你的 PHP 脚本中,写:

$stmt = $pdo->query();//<-- the query from above
$result = array();
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
    $row['pictures'] = json_decode($row['pictures'], true);
    $result[] = $row;
}

但老实说,这不值得麻烦。只需按原样执行您的查询,然后编写我在答案开头使用的那个简单循环。因为这最后一个 sn-p Though fully functional,简直是白痴。如果这确实是您希望数据库返回的那种数据,请切换到像 mongoDB 这样的NoSQL alternative,而不是重新处理此查询以最终得到只有疯子才会看到并认为它是一种可能性的东西:

SELECT
  CONCAT(
    '{"id":',
    u.id,
    ',"username":"',
    REPLACE(
      u.username,'"','&quot;'
    ),'","pictures":',
      CONCAT(
    '[',
    GROUP_CONCAT(
      CONCAT(
        '{"id":',
        p.id,
        ',"name":"',
        REPLACE(
          p.name,
          '"',
          '&quot;'
        ),
        '"}'
      )
    ),
    ']'
  ),
  '}'
) AS full_json
FROM users u
LEFT JOIN pictures p
  ON u.id = p.user_id
GROUP_BY u.id;
//in PHP:
$result = array();
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
    $result = json_decode($row['full_json'], true);

但如果您想知道:it does work

【讨论】:

  • @YourCommonSense:我不知道我在回答中明确说了多少次完全相同的事情,但我同意。我不止一次将这种创建 JSON 的业务称为 “白痴”“疯狂”...
  • 你能解释一下你的意思吗?您是否会说表示 xml 或 html 文档之类的 JSON 对象也很疯狂?如果是,为什么?在 php 中处理层次结构的更好方法?并且:您将如何代表数据库中的那些?欢迎您的解释。不解释就给出意见是没有用的
  • @Sasha:我从来没有说过(或试图说)以 JSON 格式存储东西是疯狂的。一点也不,我喜欢 JSON。但是,在 MySQL 中将数据存储为 JSON 是另一回事,尤其是当您需要查询 JSON(或 XML)对象中某处的特定值时。当您开始这样做时,要么研究 NoSQL 替代方案,要么不将数据存储为 JSON/XML 或任何其他序列化格式。对于 MySQL,JSON 只是文本,它没有被索引或解析,使用查询生成 JSON 或尝试解析 JSON 的查询是疯狂的,使用 JSON 或 XML 不是:这是常识:)
  • @Elias Van Ootegem:好的,我想我明白了,谢谢。因此,当我不想使用 NoSQL 但仍想存储面向文档的数据时,选择的方法是将这些数据分解为关系数据,然后在查询这些数据之后,a) 将其组装成使用 PHP 的 JSON 或 b) 在“关系模式”下更好地工作,并在对象级别的后续步骤中表示嵌套的 JSON 结构(例如,通过使用容器数组将底层级别的对象注入其中)?还是仅取决于大小写?如果我有这个常识,请告诉我(把这个笑话吸干;-)
  • @sasha:听起来不错……但正如您所说:这不是黑白交易:根据您的需要,将一段数据存储为 JSON 是完全可以的mysql 表中的字符串,前提是有足够的其他数据(ID 等)来查询该数据,并在关系结构中使用它。
猜你喜欢
  • 1970-01-01
  • 2012-08-08
  • 2010-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-28
  • 1970-01-01
  • 2016-07-04
相关资源
最近更新 更多