简体   繁体   English

如何在MySQL中针对特定条件进行嵌套查询

[英]How to make a nested query for a specific condition in MySQL

I have made this query where I get a list of items by their statuses and get the quantities for each status. 我进行了此查询,在其中可以获取按状态显示的项目列表,并获取每个状态的数量。 Here is the query: 这是查询:

SELECT DISTINCT (status) AS Status, COUNT(status) AS Quantity
FROM projects
GROUP BY status
ORDER BY Quantity DESC

And here are the results: 结果如下:

Status   Quantity
'PRO', 238
'TER', 75
'SUS', 14
'REI', 3

Now for those that have a 'TER' status, I want to get those 'TER' statuses that were updated or modified this year and add them to the results (excluding those 'TER' from previous years). 现在,对于那些具有“ TER”状态的产品,我想获得今年已更新或修改的那些“ TER”状态,并将它们添加到结果中(不包括往年的那些“ TER”产品)。 To do this, I have this column updated_at (so to speak). 为此,我需要将此列updated_at (可以这么说)。

How can I filter those values? 如何过滤这些值?

For example, I have tried: 例如,我尝试过:

SELECT DISTINCT (status) AS Status, COUNT(status) AS Quantity,
IF(status='TER',SELECT * FROM projects WHERE year(updated_at)=YEAR(CURDATE()))
    FROM projects
    GROUP BY status
    ORDER BY Quantity DESC

But it didn't work. 但这没有用。

Any ideas? 有任何想法吗?

Thanks for the ideas. 感谢您的想法。

Posible solution : 可能的解决方案

I have figured out another solution by using UNION: 我已经通过使用UNION找到了另一种解决方案:

(SELECT DISTINCT (status) AS Status, COUNT(status) AS Quantity,
    IF(status='TER',SELECT * FROM projects WHERE year(updated_at)=YEAR(CURDATE()))
        FROM projects
        GROUP BY status
        ORDER BY Quantity DESC)
UNION 
(
SELECT DISTINCT (status) AS Status, COUNT(status) AS Quantity,
    IF(status='TER',SELECT * FROM projects WHERE year(updated_at)=YEAR(CURDATE()))
        FROM projects
        WHERE year(updated_at) = YEAR(curdate())
        AND status IN ('TER')
        GROUP BY status
        ORDER BY Quantity DESC
)

So now I get those projects in 'TER' status and only those within the current year. 因此,现在我将那些项目设为“ TER”状态,并且只将其当年。

So the filter results for 'TER' are now (and should be less results): 因此,“ TER”的过滤器结果现在为(应该是更少的结果):

Status   Quantity
    'PRO', 238
    'SUS', 14
    'REI', 3
    'TER', 45

The problem now is that I need to reorder the results, I mean, 'TER' should be in second place... well, I have just found out here . 现在的问题是我需要重新排列结果,我的意思是,'TER'应该排在第二位...好吧,我刚刚在这里找到了。

So my final query is: 所以我的最终查询是:

SELECT * FROM (
(SELECT DISTINCT (status) AS Status, COUNT(status) AS Quantity,
        IF(status='TER',SELECT * FROM projects WHERE year(updated_at)=YEAR(CURDATE()))
            FROM projects
            GROUP BY status
            ORDER BY Quantity DESC)
    UNION 
    (
    SELECT DISTINCT (status) AS Status, COUNT(status) AS Quantity,
        IF(status='TER',SELECT * FROM projects WHERE year(updated_at)=YEAR(CURDATE()))
            FROM projects
            WHERE year(updated_at) = YEAR(curdate())
            AND status IN ('TER')
            GROUP BY status
            ORDER BY Quantity DESC
    )
) a 

GROUP BY status
ORDER BY Quantity DESC

And now I get the results I want and ordered desc: 现在,我得到了想要的结果并订购了desc:

Status   Quantity
    'PRO', 238
    'TER', 45
    'SUS', 14
    'REI', 3

Or is there a better way out there? 还是有更好的出路?

Based on the edit to the question, which now better explains the expected result, I've updated this answer with a different query. 根据对问题的编辑(现在可以更好地解释预期的结果),我用其他查询更新了此答案。 I still recommend conditional aggregation . 我仍然建议条件聚合

  SELECT p.status AS Status
       , COUNT( IF( p.status = 'TER'
                  , IF( YEAR(p.updated_at) = YEAR(CURDATE())
                      , 1
                      , NULL
                    ) 
                  , 1
                )
         ) AS Quantity
    FROM projects p
   GROUP BY p.status
   ORDER BY Quantity DESC

The line breaks and spacing aren't required... I just do that to make it easier to decipher. 不需要换行和间隔...我只是这样做,以使其更易于解密。

For a row that has status = 'TER' , it is included in the "count" only if the condition on updated_at is satisfied. 对于status = 'TER'的行,仅当满足updated_at的条件时,该行才包含在“计数”中。 For all other values of status , the row is included in the "count" for that status. 对于status所有其他值,该行包含在该状态的“ count”中。

The MySQL-specific expression: MySQL特定的表达式:

                IF( p.status = 'TER'
                  , IF( YEAR(p.updated_at) = YEAR(CURDATE())
                      , 1
                      , NULL
                    ) 
                  , 1
                )

Could be replaced with a more ANSI standards compliant expression, for example: 可以用更符合ANSI标准的表达式代替,例如:

                CASE WHEN p.status = 'TER'
                       CASE WHEN YEAR(p.updated_at) = YEAR(CURDATE()
                            THEN 1
                       END
                     ELSE 1
                END

ORIGINAL ANSWER 原始答案

What's not clear is what result you want returned. 还不清楚您想要返回什么结果。

It looks like you want an additional column returned, and it looks like you might want that to be a "count" of a subset of the rows included in the "Quantity" column. 看起来您希望返回一个附加列,并且看起来您可能希望该列成为“数量”列中所包含行的子集的“计数”。 We can do that. 我们能做到这一点。

But first, let's fix some issues with the original query. 但是首先,让我们解决原始查询的一些问题。

The keyword DISTINCT is not necessary, it's redundant with the GROUP BY . 关键字DISTINCT是不必要的,它与GROUP BY无关。 And there's no need for parens around the reference to status . 并且无需在引用status旁注。 That's not illegal to do that, but it doesn't do anything, so it's just confusing. 这样做不是违法的,但是它什么也没做,所以很混乱。 It makes it look as if someone believes that DISTINCT is a function. 它看起来好像有人认为DISTINCT是一个函数。 It's not. 不是。 It's a keyword that applies to the entire SELECT list. 这是一个关键字,适用于整个SELECT列表。

  SELECT p.status          AS Status
       , COUNT(p.status)   AS Quantity
    FROM projects p
   GROUP BY p.status
   ORDER BY Quantity DESC

It looks like you want conditional aggregation... if the updated_at is a date or datetime in the current year, then include it in the count, otherwise don't. 似乎您要进行条件汇总...如果updated_at是当前年份中的日期或日期时间,则将其包括在计数中,否则不包括在内。

  SELECT p.status          AS Status
       , COUNT(p.status)   AS Quantity
       , SUM(IF(p.status = 'TER' AND YEAR(p.updated_at)=YEAR(CURDATE()),1,NULL)) AS curcnt
    FROM projects p
   GROUP BY p.status
   ORDER BY Quantity DESC

The expression: 表达方式:

IF(p.status = 'TER' AND YEAR(p.updated_at)=YEAR(CURDATE()),1,NULL)

is MySQL shorthand. 是MySQL的简写。 An equivalent result could be obtained with a more ANSI standards compliant expression: 使用更符合ANSI标准的表达式可以获得等效的结果:

CASE WHEN p.status = 'TER' AND YEAR(p.updated_at)=YEAR(CURDATE()) THEN 1 END

Depending on how you want a count of "zero" to be displayed on that row, and other rows, you might want to use 0 in place of NULL , and/or use an expression that includes additional IF , IFNULL or NULLIF functions. 根据您希望在该行和其他行上显示“零”计数的方式,您可能希望使用0代替NULL和/或使用包含其他IFIFNULLNULLIF函数的表达式。


FOLLOWUP 跟进

The desired resultset is not clear from the question. 这个问题尚不清楚所需的结果集。

The answer above is based on the assumption that the desired result is an additional column that contains a "count" of the rows that have status='TER' and updated_at within the current year. 上面的答案基于这样的假设:期望的结果是另外一列,其中包含当年内具有status='TER'updated_at的行的“计数”。

The answer above demonstrates conditional aggregation , and does not make use of a "nested query". 上面的答案演示了条件聚合 ,并且没有使用“嵌套查询”。

A "nested query" could be used to obtain an equivalent result. “嵌套查询”可用于获取等效结果。

As an example of using a "nested query" as an inline view: 作为使用“嵌套查询”作为内联视图的示例:

  SELECT p.status                AS Status
       , COUNT(p.status)         AS Quantity
       , NULLIF(MAX(q.curcnt),0) AS curcnt
    FROM projects p
    LEFT
    JOIN ( SELECT r.status
                , COUNT(1) AS curcnt
             FROM projects r
            WHERE r.status = 'TER'
              AND YEAR(r.updated_at) = YEAR(NOW())
            GROUP BY r.status
         ) q
      ON q.status = p.status
   GROUP BY p.status
   ORDER BY Quantity DESC

And as an example of a "nested query" as a subquery in the SELECT list: 并以“嵌套查询”作为SELECT列表中的子查询的示例:

  SELECT p.status                AS Status
       , COUNT(p.status)         AS Quantity
       , NULLIF( SELECT COUNT(1)
                   FROM projects r
                  WHERE r.status = p.status
                    AND r.status = 'TER'
                    AND YEAR(r.updated_at) = YEAR(NOW())
         ,0) AS curcnt
    FROM projects p
   GROUP BY p.status
   ORDER BY Quantity DESC

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

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