php - 带变量的复杂sql查询

标签 php mysql sql pdo

这是我的查询,用于获取每个城市/子类别组合的前 $count

$contacts = $dbh->prepare("
    SELECT *
    FROM (SELECT c.*,
                 (@rn := IF(@cc = CONCAT_WS(':', city_id, subcategory_id), @rn + 1,
                            IF(@cc := CONCAT_WS(':', city_id, subcategory_id), 1, 1)
                           )
                 ) as rn
          FROM (SELECT reg.title as region_title, cnt.title, cnt.city_id, cnt.id, cnt.catalog_id, cnt.address, cnt.phone, cnt.email, cnt.website,  cnt.subcategory_title, cnt.subcategory_id, cnt.manufacturer 
                FROM contacts as cnt
                LEFT JOIN regions as reg 
                ON cnt.city_id = reg.id 
                WHERE city_id IN (".implode(',', $regions).") AND 
                      subcategory_id IN (".implode(',', $categories).") 
                ORDER BY subcategory_title, city_id, title
               ) c CROSS JOIN
               (SELECT @cc := '', @rn := 0) params
         ) c
    WHERE rn <= $count");

我正在使用 $contacts->fetchAll(PDO::FETCH_GROUP); 按 reg.title 对行进行分组

[ 
 ['City 1'] = > [ 
   [ contact 1 ],
   [ contact 2 ],
   ...
 ],
 ['City 2'] = > [ 
   [ contact 3 ],
   [ contact 4 ],
   ...
 ]
 ...
]

现在我需要升级该查询,但它对我来说太复杂了:(所选行必须具有唯一的contacts.catalog_id值。
如何做到?

UPD
这是一个演示数据库 - http://sqlfiddle.com/#!9/ac71d7/2

最佳答案

我们需要全局唯一的catalog_id

识别 catalog_id唯一值在contacts ,我们可以使用这样的查询:

   SELECT r.catalog_id
     FROM contacts r
    GROUP BY r.catalog_id
   HAVING COUNT(1) = 1

也就是说,对于 contacts 中的给定行,如果 catalog_id 的值匹配catalog_id contacts 中的任何其他行,即catalog_id将从结果中排除。

如果我们想限制原始查询仅返回 catalog_id 的值,我们可以将此查询包含为内联 View ,并将其连接到具有匹配catalog_id的联系人中的行。

<小时/>
                    FROM contacts cnt
  -- ------------
                    JOIN ( SELECT r.catalog_id
                             FROM contacts r
                            GROUP BY r.catalog_id
                           HAVING COUNT(1) = 1
                         ) s
                      ON s.catalog_id = cnt.catalog_id
  -- ------------
                    LEFT
                    JOIN regions reg
                      ON reg.id = cnt.city_id
<小时/>

编辑

如果对规范的解释不同,则代替含义 catalog_id在联系人中必须是唯一,我们的意思是 catalog_id结果中不应重复...我们可以使用相同的方法,但获取 id 的单个值来自contacts对于每个 catalog_id 。我们可以编写这样的查询:

   SELECT MAX(r.id) AS max_id
        , r.catalog_id
     FROM contacts r
    GROUP BY r.catalog_id

我们可以使用 MIN() 聚合来代替 MAX()。目标是返回单个contacts.id对于 catalog_id 的每个离散值.

我们可以将其作为内联 View 合并到查询中,匹配 max_id从内联 View 到id来自contacts表。

类似这样的事情:

                    FROM contacts cnt
  -- ------------
                    JOIN ( SELECT MAX(r.id) AS max_id
                             FROM contacts r
                            WHERE ... 
                            GROUP BY r.catalog_id
                         ) s
                      ON s.max_id = cnt.id
  -- ------------
                    LEFT
                    JOIN regions reg
                      ON reg.id = cnt.city_id

我们可能想移动 WHERE 中的条件将外部查询的子句插入到该内联 View 中。如果我们不这样做,那么 max_id内联 View 返回的可能引用 id 中的一行 ( contacts )不满足 WHERE 中的条件条款。

重新定位WHERE条件cnt进入内联 View ...

SELECT d.*
  FROM ( SELECT c.*
              , ( @rn := IF( @cc = CONCAT_WS(':', city_id, subcategory_id)
                           , @rn + 1
                           , IF( @cc := CONCAT_WS(':', city_id, subcategory_id),1,1)
                         )
                ) AS rn
           FROM ( SELECT reg.title AS region_title
                       , cnt.title
                       , cnt.city_id
                       , cnt.id
                       , cnt.catalog_id
                       , cnt.address
                       , cnt.phone
                       , cnt.email
                       , cnt.website
                       , cnt.category_title
                       , cnt.subcategory_title
                       , cnt.subcategory_id
                       , cnt.manufacturer
                    FROM contacts cnt
  -- --------------
                    JOIN ( SELECT MAX(r.id) AS max_id
                             FROM contacts r
                            WHERE r.city_id        IN ( ... ) 
                              AND r.subcategory_id IN ( ... )
                              AND r.email          IS NOT NULL
                              AND r.manufacturer   = 1
                            GROUP BY r.catalog_id
                         ) s
                      ON s.max_id = cnt.id
  -- --------------
                    LEFT
                    JOIN regions reg
                      ON reg.id = cnt.city_id
                   ORDER
                      BY cnt.category_title
                       , cnt.subcategory_title
                       , cnt.city_id
                       , cnt.title
                ) c
          CROSS
           JOIN ( SELECT @cc := '', @rn := 0) i
       ) d
 WHERE d.rn <= 10
<小时/>

关于php - 带变量的复杂sql查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47763516/

相关文章:

PHP - 将日期放入 MySQL 表

MySQL 分别select WHERE a IN (..) AND b IN (..)

MySQL ALL 运算符的问题

MySQL - 如何删除多对多关系中的相关行

sql - PostgreSQL 9.3。没有所有列的分组依据

php - 从 JavaScript 到 PHP 的变量

javascript - 如何在 javascript 中使用存储在服务器中的对象?

php - 为什么 mysql_real_escape_string 在不应该的地方插入引号?

php - PayPal IPN 记录但未插入 MySQL

mysql - 值为整数时删除记录