带变量的复杂sql查询

时间:2017-12-12 00:16:29

标签: 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

1 个答案:

答案 0 :(得分:1)

我们需要全局唯一的catalog_id

要识别catalog_idcontacts唯一值,我们可以使用如下查询:

   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的值,我们可以将此查询包含为内联视图,并将其连接到具有匹配的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 我们可以使用相同的方法,但每个contactscatalog_id获得 SELECT MAX(r.id) AS max_id , r.catalog_id FROM contacts r GROUP BY r.catalog_id 的单个值。我们可以写一个这样的查询:

contacts.id

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

我们可以将其作为内联视图合并到查询中,将内联视图中的idcontacts表中的 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

我们可能希望将外部查询的max_id子句中的条件移动到该内联视图中。如果我们不这样做,那么内联视图返回的id可能引用contacts中不满足WHERE子句中条件的行(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 条件重新定位到内联视图...

Session session = sessionFactory.openSession();
session.beginTransaction();
String sql = "select First_Name FROM employee where First_Name like 'NAME%'"
NativeQuery query = session.createNativeQuery(sql);
List<Object[]> list = query.list();
if (list.isEmpty()) {
session.persist(emp);
}