简体   繁体   English

带有变量的复杂SQL查询

[英]Complicated sql query with variables

That's my query to get first $count rows for each city/subcategory combination 这是我的查询,以获取每个城市/子类别组合的第一个$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");

And i'm using $contacts->fetchAll(PDO::FETCH_GROUP); 我正在使用$contacts->fetchAll(PDO::FETCH_GROUP); to group rows by reg.title 按标题对行进行分组

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

Now I need to upgrade that query but it's too complicated for me :( Selected rows must have unique contacts.catalog_id value. 现在我需要升级该查询,但对我来说太复杂了:(选定的行必须具有唯一的contact.catalog_id值。
How it can be done? 怎么做?

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

" We need unique catalog_id globally " 我们需要全局唯一的catalog_id

To identify unique values of catalog_id in contacts , we could use a query like this: 为了识别contactscatalog_id 唯一值,我们可以使用如下查询:

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

That says, for a given row in contacts , if the value of catalog_id matches catalog_id on any other row in contacts , that catalog_id will be excluded from the result. 这表示,在给定的行contacts ,如果价值catalog_id匹配catalog_id任何其他contacts ,这catalog_id将被从结果中排除。

If we want to restrict the original query to returning only those values of catalog_id , we could include this query as an inline view, and join that to rows in contacts with matching catalog_id. 如果我们希望将原始查询限制为仅返回那些catalog_id值,则可以将该查询作为内联视图包括在内,并将其连接到与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

EDIT 编辑

If the specification is interpreted differently, instead of meaning catalog_id must be unique in contacts, we mean that a catalog_id should not be repeated in the result... we can use the same approach, but get single value of id from contacts for each catalog_id . 如果规范有不同的解释,而不是意catalog_id必须是唯一的接触,我们的意思是一个catalog_id不应该在结果重复......我们可以用同样的方法,但得到的单值idcontacts的每个catalog_id We could write a query like this: 我们可以这样写一个查询:

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

We could use MIN() aggregate in place of MAX(). 我们可以使用MIN()聚合代替MAX()。 The goal is to return a single contacts.id for each discrete value of catalog_id . 我们的目标是返回一个contacts.id的每个离散值catalog_id

We can incorporate that into the query as an inline view, matching max_id from the inline view to the id from contacts table. 我们可以将其作为内联视图合并到查询中,使内联视图中的max_idcontacts中的id匹配。

Something like this: 像这样:

                    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

We probably want to move the conditions in the WHERE clause of the outer query into that inline view. 我们可能希望将外部查询的WHERE子句中的条件移动到该内联视图中。 If we don't, then the max_id returned by the inline view might reference an row ( id ) in contacts that doesn't satisfy the conditions in the WHERE clause. 如果不这样做,那么内联视图返回的max_id可能会引用不满足WHERE子句条件的contacts中的行( id )。

Relocating the WHERE conditions on cnt into the inline view ... 重新定位WHERE上条件cnt入联视图...

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM