【问题标题】:Semi-complicated doctrine query半复杂的学说查询
【发布时间】:2011-09-16 21:41:33
【问题描述】:

我有一个查询要写,这对我来说有点太复杂了。帮助将不胜感激。 我的桌子本质上是:

Table: Foo
Columns: id
         timestamp
         bar1
         bar2
         bar3

Bar1、bar2 和 bar3 对于每条记录来说不是唯一的。实际上,这三者的组合具体涉及多条记录。例如:

0 | 2011-01-01 00:01:01 | 100 | 5 | 'Hello'
1 | 2011-01-01 12:12:00 | 100 | 5 | 'Hello'
2 | 2011-01-01 07:43:00 | 101 | 8 | 'Monkey'
3 | 2011-01-01 17:46:08 | 102 | 9 | 'Cat'
4 | 2011-01-01 23:15:00 | 100 | 5 | 'Hello'
5 | 2011-01-01 10:00:00 | 100 | 6 | 'Goodbye'

记录 0、1 和 4 是相关的,而 2、3 和 5 是唯一的。

考虑到这一点,我想查找所有 bar1 == 100、bar2 == 5 和 bar3 == 'Hello' 的记录,IF 组中的所有记录都有时间戳 OR 组中的一条记录具有时间戳

希望这是有道理的。如果没有,请告诉我,我会尽力澄清。

编辑:我希望只有 bar 就足以作为示例,但实际上我的实际表有多个列必须匹配以指示记录是相关的。我已经相应地更新了这个例子。

【问题讨论】:

  • 我不知道你的数据,但看起来 {bar1,bar2,bar3} 组成了一个可以“规范化”到单独表格中的组。

标签: php sql postgresql doctrine-orm


【解决方案1】:

如果我正确理解了您的问题,您想要所有记录为 (bar1, bar2, bar3) = (100, 5, 'Hello') 并且您拥有某些current_time 作为唯一的一个输入标准。

作为第一步,我重新表述两个条件:为了检索组的成员,组的最大时间戳必须在过去(您的第一个条件)或组的最小时间戳必须至少 30 分钟(相当于到你的第二个条件)。

因此您可以使用此查询查看组及其时间戳:

    SELECT bar1, bar2, bar3, max(timestamp) group_end, min(timestamp) group_start 
        FROM foo 
        GROUP BY bar1, bar2, bar3;

添加过滤器:(注意 psql 的特殊语法,用于 \set: - 这仅用于测试)

    \set current_time '''2011-01-01 17:00:00'''
    SELECT bar1, bar2, bar3, max(timestamp) group_end, min(timestamp) group_start 
        FROM foo 
        GROUP BY bar1, bar2, bar3 
        HAVING max(timestamp)  <= :current_time OR min(timestamp) +'30min' <= :current_time

这不会为current_time = 2011-01-01 00:31:00 返回任何内容,因为没有组已完成,也没有未完成的组 id 足够老。之后由于 OR 子句返回 (100, 5, Hello) 组,并在进一步增加 current_time 的同时返回另一个组。

到目前为止一切顺利 - 最后一部分是检索所有找到的组的成员:

    SELECT * FROM foo WHERE (bar1, bar2, bar3) in (
        SELECT bar1, bar2, bar3 FROM foo 
        -- add WHERE clause with constraints based on bar1, bar2, bar3 here
        GROUP BY bar1, bar2, bar3 
        HAVING max(timestamp)  <= :current_time OR min(timestamp) +'30min' <= :current_time
    )
    -- add further constraints here

如果我对您的输入参数的第一个假设是错误的,您当然可以在查询的每个合适的步骤中添加过滤器。当然,在更早的步骤中进行过滤会更高效。我添加了合适的标记 cmets。

【讨论】:

    【解决方案2】:

    我对 postgresql 不是很熟悉,但这是 T-SQL 中的一个答案,它应该返回您正在寻找的结果。我不认为它使用 postgresql 中不可用的任何命令,但我不确定。此外,它可能会阻塞子选择中的 DISTINCT,如果是这样,只需将其删除,因为它不是必需的。祝你好运。

    SELECT *
    FROM Foo
    WHERE 
    (
    bar IN (SELECT bar 
            FROM (SELECT bar, MAX(timestamp) As HighestTime FROM Foo GROUP BY bar) HT 
            WHERE HT.HighestTime <= GETDATE())
    OR bar IN (SELECT DISTINCT bar FROM Foo WHERE timestamp <= DATEADD(mm, -30, GETDATE())
    ) 
    AND
    bar = 100
    

    第一个“bar in”使用子选择仅通过检查最大的一个来获取所有时间戳低于或等于当前日期时间的那些 bar 编号。

    第二个“bar in”使用子选择来获取至少有 1 条记录且时间戳小于或等于当前时间 - 30 分钟的任何 bar 编号。

    “bar =”只是将其限制为特定的条号。

    【讨论】:

    • 如果 bar 实际上是 bar1、bar2、bar3,您将如何调整?
    猜你喜欢
    • 1970-01-01
    • 2014-04-27
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 2012-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多