【问题标题】:trying to combine two nested queries for efficiency试图结合两个嵌套查询以提高效率
【发布时间】:2014-03-08 20:21:07
【问题描述】:

我有两个嵌套查询,第二个在我遍历第一个的结果时运行。我想让 MySQL 服务器代替 PHP 来完成这项工作,但我不知道如何将这两者结合起来。

第一个查询:

SELECT post_id,
       MAX(CASE WHEN meta_key = 'size' THEN meta_value END) size,
       MAX(CASE WHEN meta_key = 'adlink' THEN meta_value END) adlink,
       MAX(CASE WHEN meta_key = 'frontpage' THEN meta_value END) frontpage,
       MAX(CASE WHEN meta_key = 'expiration' THEN meta_value END) expiration,
       MAX(CASE WHEN meta_key = 'image1' THEN meta_value END) image1,
       MAX(CASE WHEN meta_key = 'image2' THEN meta_value END) image2,
       MAX(CASE WHEN meta_key = 'image3' THEN meta_value END) image3,
       MAX(CASE WHEN meta_key = 'image4' THEN meta_value END) image4,
       MAX(CASE WHEN meta_key = 'iframe' THEN meta_value END) iframe,
       MAX(CASE WHEN meta_key = 'location' THEN meta_value END) location,
       MAX(CASE WHEN meta_key = 'sublocation' THEN meta_value END) sublocation
    FROM wp_postmeta WHERE post_id in 
      (SELECT post_id from wp_postmeta 
       WHERE meta_value LIKE 'Run Of Site') GROUP BY Post_id

然后,遍历结果,我们从另一个表中获取图像,如'image1'等,只是第一组结果中的post id号:

SELECT meta_value FROM wp_postmeta 
   WHERE post_id IN
     (SELECT meta_value from wp_postmeta 
      WHERE post_id = " . $row{'post_id'} ." AND meta_key like 'image%')

这里是查看 PHP 迭代的完整代码(我知道它需要更好的格式以提高可读性):

$rosads = mysql_query("SELECT post_id,
       MAX(CASE WHEN meta_key = 'size' THEN meta_value END) size,
       MAX(CASE WHEN meta_key = 'adlink' THEN meta_value END) adlink,
       MAX(CASE WHEN meta_key = 'frontpage' THEN meta_value END) frontpage,
       MAX(CASE WHEN meta_key = 'expiration' THEN meta_value END) expiration,
       MAX(CASE WHEN meta_key = 'image1' THEN meta_value END) image1,
       MAX(CASE WHEN meta_key = 'image2' THEN meta_value END) image2,
       MAX(CASE WHEN meta_key = 'image1' THEN meta_value END) image3,
       MAX(CASE WHEN meta_key = 'image2' THEN meta_value END) image4,
       MAX(CASE WHEN meta_key = 'iframe' THEN meta_value END) iframe,
       MAX(CASE WHEN meta_key = 'location' THEN meta_value END) location,
       MAX(CASE WHEN meta_key = 'sublocation' THEN meta_value END) sublocation
    FROM wp_postmeta WHERE post_id in (SELECT post_id from wp_postmeta WHERE meta_value LIKE 'Run Of Site') GROUP BY Post_id");
if (!$rosads) { // add this check.
    die('Invalid query: ' . mysql_error());
}

    while ($row = mysql_fetch_array($rosads)) {   // #########  ITERATE THROUGH THE LIST

        if ($row{'size'} == "Premium"){
            if ($row{'iframe'}){
                $premium = $premium . '<div name="PREMIUM'.$row{'post_id'}.'" style="float:left;">'.$row{'iframe'}.'</div>'."\n";
            }else{
                $images = mysql_query("SELECT meta_value FROM wp_postmeta where post_id IN(SELECT meta_value from wp_postmeta WHERE post_id = " . $row{'post_id'} ." AND meta_key like 'image%')");
                $premium = $premium . "<div name=\"".$row{'post_id'}."\" class=\"multipleslides\" >";
                while ($row2 = mysql_fetch_array($images)) {
                    $premium = $premium . "\t<a target=\"_blank\" href=\"" . $row{'adlink'} ."\"><img src=\"/wp-content/uploads/" .$row2{'meta_value'} ."\"></a>\r\n";
                }
                $premium = $premium . "</div><br>";
            }
        /* ### TEST STUFF ####
        echo $row{'post_id'} . ", " . $row{'size'} . ", " . $row{'adlink'} . ", " . $row{'frontpage'} . ", " . $row{'expiration'} . ", " . $row{'image1'} . ", " . $row{'image2'} . ", " . $row{'image3'} . ", " . $row{'image4'} . ", " . 1$row{'location'} . ", " . $row{'sublocation'} . ", " . $row{'iframe'} . "<hr>";
        */
        } // ###### END THIS ITERATION ####

【问题讨论】:

  • 你想做什么? SO 上的很多人都了解 WordPress 架构,因此它可能有助于说明您的意图。
  • 尝试使用现有的 wp_postmeta 表及其结构创建自定义广告插件 - 这是我的第一个错误......创建一个新表会更容易...... :-(

标签: php mysql sql wordpress


【解决方案1】:

您也可以将查询用作列,但确保您的子查询应返回一条记录,以确保安全我已在子查询中添加了LIMIT 1,或者如果有超过 1 个结果,您可以删除限制并可以使用 @987654323 @ 但知道它的默认限制为 1024 个字符

SELECT wpm.post_id,
       MAX(CASE WHEN wpm.meta_key = 'size' THEN wpm.meta_value END) size,
       MAX(CASE WHEN wpm.meta_key = 'adlink' THEN wpm.meta_value END) adlink,
       MAX(CASE WHEN wpm.meta_key = 'frontpage' THEN wpm.meta_value END) frontpage,
       MAX(CASE WHEN wpm.meta_key = 'expiration' THEN wpm.meta_value END) expiration,
       MAX(CASE WHEN wpm.meta_key = 'image1' THEN wpm.meta_value END) image1,
       MAX(CASE WHEN wpm.meta_key = 'image2' THEN wpm.meta_value END) image2,
       MAX(CASE WHEN wpm.meta_key = 'image3' THEN wpm.meta_value END) image3,
       MAX(CASE WHEN wpm.meta_key = 'image4' THEN wpm.meta_value END) image4,
       MAX(CASE WHEN wpm.meta_key = 'iframe' THEN wpm.meta_value END) iframe,
       MAX(CASE WHEN wpm.meta_key = 'location' THEN wpm.meta_value END) location,
       MAX(CASE WHEN wpm.meta_key = 'sublocation' THEN wpm.meta_value END) sublocation,
(
SELECT 
  meta_value 
FROM
  wp_postmeta 
WHERE post_id IN 
  (SELECT 
    meta_value 
  FROM
    wp_postmeta 
  WHERE post_id = wpm. post_id
    AND meta_key LIKE 'image%')
LIMIT 1) images       

    FROM wp_postmeta wpm WHERE wpm.post_id IN 
      (SELECT post_id FROM wp_postmeta 
       WHERE meta_value LIKE 'Run Of Site') GROUP BY wpm.post_id

对于group_concat()

(
SELECT 
 GROUP_CONCAT(meta_value)
FROM
  wp_postmeta 
WHERE post_id IN 
  (SELECT 
    meta_value 
  FROM
    wp_postmeta 
  WHERE post_id = wpm. post_id
    AND meta_key LIKE 'image%')
) images  

【讨论】:

  • 嗯,这让我得到了一个有趣的,如果神秘的回应:Invalid query: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(SELECT meta_value FROM wp_postmeta WHERE post_id IN (SELECT meta_value FROM wp_' at line 13
  • 向我展示你正在尝试的整个查询我猜sublocation 可能是逗号之后缺少一些东西
  • 我想,理想情况下,我正在尝试将该查询插入到 image1、image2 等被格式化为列的位置 - (MAX() 行),以便我得到图像来自第二个查询的 url 而不是来自第一个查询的 id。
  • 我将在上面发布整篇文章,您可以在其中查看格式。
  • @DavidMcClave 你能在sqlfiddle添加表定义和示例数据集吗
【解决方案2】:

为提高效率,请将IN (subquery) 替换为等效的连接操作,并确保您有合适的索引。

在第一个查询中,替换为:

    FROM wp_postmeta WHERE post_id in 
      (SELECT post_id from wp_postmeta 
       WHERE meta_value LIKE 'Run Of Site') GROUP BY Post_id

用这个:

   FROM wp_postmeta m
   JOIN ( SELECT r.post_id 
            FROM wp_postmeta r
           WHERE r.meta_value LIKE 'Run Of Site'
          GROUP BY r.post_id
        ) q
     ON q.post_id = m.post_id 
  GROUP BY m.post_id

AND将 SELECT 列表中的 post_id 引用更改为 m.post_id(以避免“模糊列”引用错误。)

对于第二个查询,将“IN(子查询)”替换为 JOIN 操作:

SELECT t.meta_value
  FROM wp_postmeta t
  JOIN ( SELECT q.meta_value
           FROM wp_postmeta q 
          WHERE q,meta_key LIKE 'image%'
            AND q.post_id = " . $row{'post_id'} ."
       ) s
    ON s.meta_value = t.meta_value
 ORDER BY t.meta_value

组合这两个查询是有问题的,因为第二个查询可以返回多个匹配 post_id 的行。

要返回结果集,我们需要定义该结果集的外观。

共有三种通用方法。简而言之,

一种方法是“重复”第一个查询返回的值,但这看起来不太适合您当前的代码。 “获取下一个”需要检查 post_id 是否已被处理,并忽略重复值。 (这是几个 ORM 框架用来提高效率的方法;它们有一个代码层,可以去除重复项,并创建不同的对象。)

另一种方法是从第二个查询返回固定数量的值,每个值作为第二个中的一列。请注意,SQL SELECT 语句必须定义要返回的列数和每列的数据类型。查询运行时不能动态更改。如果我们可以指定要返回的行数的有限上限,那么我们可以制作 SQL 文本来完成此操作,尽管结果语句可能有点令人生畏,并且存在一些性能问题。

返回“一组”值最方便的方法是将它们作为单个字符串返回,并带有分隔符。 MySQL GROUP_CONCAT 函数是一种非常方便的方法,但有一些限制。首先,我们必须在值之间有一个分隔符;默认分隔符是逗号,但可以使用任何字符(“管道”字符似乎很流行......为了避免歧义,我们必须保证分隔符不会出现在连接在一起的值中。其他限制是函数返回的大小;最大大小受 MySQL max_allowed_packet 变量的限制。


【讨论】:

  • 非常好,非常彻底的答案!非常感谢!
猜你喜欢
  • 2014-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-12
  • 1970-01-01
  • 2022-01-02
  • 1970-01-01
相关资源
最近更新 更多