HAVING子句与聚合函数和NOT IN的组合未按预期生效。

huangapple go评论49阅读模式
英文:

Having clause with aggregate and NOT IN doesn't apply both as expected

问题

我正在尝试从以下示例中选择最近三年内Vigor值为6、8或9的树木。因此,在下面的网格中,我想要所有TreeID为2和3的行,但不包括任何TreeID为1的行。

SELECT PlotID, TreeID, Vigor, count(*) c
FROM tblTreeInfo
GROUP BY PlotID, TreeID, Vigor
HAVING (c < 3 AND Vigor NOT IN (6, 8, 9))

所以,我尝试了这个,但这会排除TreeID为2,因为它的Vigor值为8,但只有1年。

SELECT PlotID, TreeID, Vigor, count(*) c
FROM tblTreeInfo
WHERE Vigor NOT IN (6, 8, 9)
GROUP BY PlotID, TreeID, Vigor
HAVING (c < 3)

我该如何获得同时满足Vigor不为6、8、9和c < 3的行?谢谢!

英文:

I'm trying to select trees from the following sample that have had the Vigor value 6,8 or 9 for the past three years straight. So, in the below grid I would want all rows with TreeID 2 and 3, but not any with TreeID 1.

PlotID    ObsYear TreeID Vigor
MACFI0407 2020    1      8
MACFI0407 2021    1      8
MACFI0407 2022    1      8
MACFI0407 2020    2      1
MACFI0407 2021    2      1
MACFI0407 2022    2      8
MACFI0407 2020    3      1
MACFI0407 2021    3      1
MACFI0407 2022    3      1

This is what I thought I wanted, but it doesn't seem like mySQL is using the 'AND' to mean BOTH. This is leaving out TreeID 3 since it has a count of 3 (but Vigor value was 1)

SELECT PlotID, TreeID, Vigor, count(*) c
FROM tblTreeInfo
GROUP BY PlotID, TreeID, Vigor
HAVING (c &lt; 3 AND Vigor NOT IN (6, 8, 9))

So I tried this, but this leaves out TreeID 2, since it has Vigor 8, but only for 1 year.

SELECT PlotID, TreeID, Vigor, count(*) c
FROM tblTreeInfo
WHERE Vigor NOT IN (6, 8, 9)
GROUP BY PlotID, TreeID, Vigor
HAVING (c &lt; 3)

How can I get rows with both vigor not 6,8,9 AND c<3? Thank you!

答案1

得分: 0

以下是翻译好的代码部分:

你想要过去三年(2020年至2022年)的数据。首先要获取这些年份的数据行。然后,你想要排除这些年份中出现过689级别的树木ID。通过统计这些年份中出现这些级别的不同年份来找到这些ID,然后选择排除这些ID的数据行

    with rows_of_interest as
    (
      select *
      from mytable
      where obsyear between year(curdate()) - 3 and year(curdate()) - 1
    )
    select *
    from rows_of_interest
    where treeid not in
    (
      select treeid
      from rows_of_interest
      where vigor in (6, 8, 9)
      group by treeid
      having count(distinct obsyear) = 3
    )
    order by treeid, obsyear;

演示链接:https://dbfiddle.uk/DeRhqRoX
英文:

You want the last three years (2020 to 2022). Getting these rows is the first step. Then you want to omit tree IDs that had vigor 6, 8 or 9 in each of these years. Find these IDs, by counting distinct years in which these vigors occured. Then select the rows omitting these IDs.

with rows_of_interest as
(
  select *
  from mytable
  where obsyear between year(curdate()) - 3 and year(curdate()) - 1
)
select *
from rows_of_interest
where treeid not in
(
  select treeid
  from rows_of_interest
  where vigor in (6, 8, 9)
  group by treeid
  having count(distinct obsyear) = 3
)
order by treeid, obsyear;

Demo: https://dbfiddle.uk/DeRhqRoX

答案2

得分: 0

以下是代码的翻译部分:

## 过去3年内生长不旺盛的树木
SELECT
  T.*
FROM mytable AS T
LEFT JOIN (
        SELECT treeid
        FROM mytable
        GROUP BY treeid
        HAVING (MAX(CASE WHEN obsyear = year(curdate()) - 3 AND vigor IN (6,8,9) THEN 1 ELSE 0 END)
              + MAX(CASE WHEN obsyear = year(curdate()) - 2 AND vigor IN (6,8,9) THEN 1 ELSE 0 END)
              + MAX(CASE WHEN obsyear = year(curdate()) - 1 AND vigor IN (6,8,9) THEN 1 ELSE 0 END)) = 3
        ) AS VIGOR ON T.TREEID = VIGOR.TREEID
WHERE VIGOR.TREEID IS NULL
## 过去3年内生长旺盛的树木
SELECT
  T.*
FROM mytable AS T
INNER JOIN (
        SELECT treeid
        FROM mytable
        GROUP BY treeid
        HAVING (MAX(CASE WHEN obsyear = year(curdate()) - 3 AND vigor IN (6,8,9) THEN 1 ELSE 0 END)
              + MAX(CASE WHEN obsyear = year(curdate()) - 2 AND vigor IN (6,8,9) THEN 1 ELSE 0 END)
              + MAX(CASE WHEN obsyear = year(curdate()) - 1 AND vigor IN (6,8,9) THEN 1 ELSE 0 END)) = 3
        ) AS VIGOR ON T.TREEID = VIGOR.TREEID

请注意,这些翻译仅包括代码部分,不包括问题或其他内容。

英文:
## TREES THAT ARE NOT VIGOROUS OVER PAST 3 YEARS
SELECT
  T.*
FROM mytable AS T
LEFT JOIN (
        SELECT treeid
        FROM mytable
        GROUP BY treeid
        HAVING (MAX(CASE WHEN obsyear = year(curdate()) - 3 AND vigor IN (6,8,9) THEN 1 ELSE 0 END)
              + MAX(CASE WHEN obsyear = year(curdate()) - 2 AND vigor IN (6,8,9) THEN 1 ELSE 0 END)
              + MAX(CASE WHEN obsyear = year(curdate()) - 1 AND vigor IN (6,8,9) THEN 1 ELSE 0 END)) = 3
        ) AS VIGOR ON T.TREEID = VIGOR.TREEID
WHERE VIGOR.TREEID IS NULL
plotid obsyear treeid vigor
MACFI0407 2020 2 1
MACFI0407 2021 2 1
MACFI0407 2022 2 8
MACFI0407 2020 3 1
MACFI0407 2021 3 1
MACFI0407 2022 3 1
MACFI0407 2020 4 6
MACFI0407 2020 4 8
MACFI0407 2020 4 9
## TREES THAT ARE VIGOROUS OVER PAST 3 YEARS
SELECT
  T.*
FROM mytable AS T
INNER JOIN (
        SELECT treeid
        FROM mytable
        GROUP BY treeid
        HAVING (MAX(CASE WHEN obsyear = year(curdate()) - 3 AND vigor IN (6,8,9) THEN 1 ELSE 0 END)
              + MAX(CASE WHEN obsyear = year(curdate()) - 2 AND vigor IN (6,8,9) THEN 1 ELSE 0 END)
              + MAX(CASE WHEN obsyear = year(curdate()) - 1 AND vigor IN (6,8,9) THEN 1 ELSE 0 END)) = 3
        ) AS VIGOR ON T.TREEID = VIGOR.TREEID
plotid obsyear treeid vigor
MACFI0407 2020 1 8
MACFI0407 2021 1 8
MACFI0407 2022 1 8
MACFI0407 2020 5 6
MACFI0407 2021 5 8
MACFI0407 2022 5 9
MACFI0407 2023 5 9
MACFI0407 2020 5 6
MACFI0407 2020 5 8
MACFI0407 2022 5 9
MACFI0407 2022 5 9

fiddle

答案3

得分: -1

一个简单的方法是包含 count(*) = 3,因为只有最近3年具有 Vigor IN (6, 8, 9) 的树木必须被忽略:

with cte as (
  SELECT PlotID, TreeID, Vigor, count(*) c
  FROM mytable
  GROUP BY PlotID, TreeID, Vigor
  HAVING (c <= 3 AND Vigor NOT IN (6, 8, 9))
)
select t.*
from mytable t
inner join cte c on c.TreeID = t.TreeID

示例在这里

英文:

A Simple way to do it, is to include count(*) = 3 since only Trees with last 3 years having Vigor IN (6, 8, 9) must be ignored :

with cte as (
  SELECT PlotID, TreeID, Vigor, count(*) c
  FROM mytable
  GROUP BY PlotID, TreeID, Vigor
  HAVING (c &lt;= 3 AND Vigor NOT IN (6, 8, 9))
)
select t.*
from mytable t
inner join cte c on c.TreeID = t.TreeID

Demo here

huangapple
  • 本文由 发表于 2023年3月4日 03:19:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/75631083.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定