【问题标题】:SQL select with COUNT(*) > minimum numberSQL select with COUNT(*) > minimum number
【发布时间】:2018-03-11 21:54:26
【问题描述】:

我有两张桌子。一店“地点”:

TABLE location (
    ID               serial             PRIMARY KEY,
    name             text               NOT NULL,
    description      text               NOT NULL
);

每个位置都有很多行“数据”:

TABLE data(
    ID               smallint           REFERENCES location(ID),
    date             date,               
    rainfall         int                
);

我想查找所有具有跨越给定时间段的“数据”的位置,并且在该时间段内至少具有“最小”个值。我试过这个:

SELECT location.ID, location.name 
FROM location 
JOIN data 
ON data.id = location.id 
GROUP BY location.id 
HAVING MIN(data.date) <= '$start_date' 
       AND
       MAX(data.date) >= '$end_date'  
       AND 
       (SELECT COUNT(*) FROM data WHERE data.date >= '$start_date' AND data.date <= '$end_date') >= '$min' 
ORDER BY location.ID

如果我取出倒数第二行(SELECT COUNT 行),它会正确返回具有跨越所需时间段的数据的位置(但不存在所需时间段内值的数量大于或等于的约束)到“分钟”)。

谁能告诉我如何施加约束? IE。我的“SELECT COUNT 行”出了什么问题。

以下示例数据可能有助于澄清我的问题:

示例数据:

location:
ID = 1, name = "London",   description = "test location 1"
ID = 2, name = "New York", description = "test location 2"

数据:

ID = 1, date = 2001-01-01, rainfall = 0.0
ID = 1, date = 2001-01-02, rainfall = 0.0
ID = 1, date = 2001-01-03, rainfall = 0.0
ID = 1, date = 2001-01-04, rainfall = 0.0
ID = 1, date = 2001-01-05, rainfall = 0.0
ID = 1, date = 2001-01-06, rainfall = 0.0
ID = 1, date = 2001-01-07, rainfall = 0.0

ID = 2, date = 2001-01-01, rainfall = 0.0
ID = 2, date = 2001-01-04, rainfall = 0.0
ID = 2, date = 2001-01-05, rainfall = 0.0
ID = 2, date = 2017-01-01, rainfall = 0.0  # Not within the desired period, so is excluded
ID = 2, date = 2017-01-02, rainfall = 0.0  # Not within the desired period, so is excluded
ID = 2, date = 2017-01-03, rainfall = 0.0  # Not within the desired period, so is excluded
ID = 2, date = 2017-01-04, rainfall = 0.0  # Not within the desired period, so is excluded

如果我搜索数据介于 2001-01-01 和 2001-01-07 之间的所有位置,并且至少有 6 个数据值,它应该只返回位置 1 (ID=1)。不应返回第二个位置 (ID=2),因为它在所需时间段内没有所需数量的值。

【问题讨论】:

  • 这个问题在我看来已经够清楚了。

标签: sql postgresql select


【解决方案1】:

这是我的答案的新版本,因为我误解了“跨越”。我对这个问题的解释仍然是,在计算值时,我们应该只在给定的时间段内进行计算

SELECT l.id, l.name 
FROM location l
JOIN location_data d 
ON l.id = d.id 
GROUP BY l.id, l.name
HAVING MIN(d.date) <= '2017-01-01' 
   AND MAX(d.date) >= '2017-12-31'  
   AND (SELECT COUNT(b.id)
        FROM location_data b
        WHERE b.date BETWEEN '2017-01-01' AND '2017-12-31' 
        AND b.id = l.id) >= 2

我在测试数据库中将表数据重命名为 location_data 但这可能很明显 :)

【讨论】:

  • 我不知道 PostreSQL,所以我只是问:你确定这个查询有效吗?我担心 GROUP BY 子句;在 Oracle 中,它应该包含 SELECT 中包含的所有列,否则会失败。我相信 PostgreSQL 也是如此(至少,这是我在 SQL Fiddle 上所经历的)。
  • 这也没有实现用户描述的逻辑。
  • @Littlefoot,你说得对,SELECT 和 GROUP BY 应该匹配。我会更新我的回复。
  • @GordonLinoff,您能详细说明一下吗?
  • @JoakimDanielson 。 . .这仅确定两个限制之间是否存在日期。问题很明显是检查期间之前和之后的日期。
【解决方案2】:

首先,您应该将日期等值作为参数 传递,而不是作为字符串传递。其次,COUNT() 返回一个数字,所以比较应该是一个数字,而不是一个字符串。

您应该能够使用group byhaving 做您想做的事情。一种方法是:

SELECT l.ID, l.name 
FROM location l JOIN
     data d
     ON d.id = l.id 
GROUP BY l.id, l.name
HAVING MIN(d.date) <= '$start_date' AND
       MAX(d.date) >= '$end_date' AND
       COUNT(*) >= $min
ORDER BY l.ID;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 2020-11-12
    • 2015-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多