sqlite3 按最大值查询并按第二个因素过滤

Posted

技术标签:

【中文标题】sqlite3 按最大值查询并按第二个因素过滤【英文标题】:sqlite3 query by max and filter by second factor 【发布时间】:2015-12-28 04:23:42 【问题描述】:

我有:

TABLE MESSAGES
 message_id | conversation_id | from_user | timestamp  |  message

我想要:

1. SELECT * WHERE from_user <> id 
2. GROUP BY conversation_id
3. SELECT in every group row with MAX(timestamp) **(if there are two same timestamps in a group use second factor as highest message_id)** !!!
4. then results SORT BY timestamp 

有结果:

2|145|xxx|10000|message

6|1743|yyy|999|message

7|14|bbb|899|message

淘汰

1|145|xxx|10000|message    <- has same timestamp(10000) as message(2) belongs to the same conversation(145) but message id is lowest  

5|1743|me|1200|message <- has message_from == me 

具有相同时间戳的示例组

我想从这个组第 3 行,但我从查询中得到第 2 行

SELECT max(message_timestamp), message_id, message_text, message_conversationId
FROM MESSAGES
WHERE message_from <> 'me'
GROUP BY message_conversationId
ORDER by message_Timestamp DESC

我的想法是从 message_id 和时间戳进行联合,然后得到最大值???

【问题讨论】:

用样本数据准备sqlfiddle.com 投票将其迁移到 DBA.SE(因为它已在那里交叉发布:dba.stackexchange.com/questions/116123/…),因此它们可以合并。 【参考方案1】:

您的查询基于 GROUP BY 的非标准使用(我认为 SQLite 仅允许与 mysql 兼容),我完全不确定它是否会一直产生确定的结果。

另外,它在连接列上使用MAX()。除非您以某种方式确保两个(连接的)列具有固定宽度,否则结果也不会因此而准确。

我会这样写查询:

SELECT 
    m.message_timestamp, 
    m.message_id, 
    m.message_text,
    m.message_conversationId
FROM 
    ( SELECT message_conversationId         -- for every conversation
      FROM messages as m
      WHERE message_from <> 'me'            
      GROUP BY message_conversationId
    ) AS mc
  JOIN 
    messages AS m                           -- join to the messages
      ON  m.message_id =        
          ( SELECT mi.message_id            -- and find one message id
            FROM messages AS mi
            WHERE mi.message_conversationId      -- for that conversation
                  = mc.message_conversationId
              AND mi.message_from <> 'me'
            ORDER BY mi.message_timestamp DESC,  -- according to the
                     mi.message_id DESC          -- specified order
            LIMIT 1                              -- (this is the one part)
          ) ;

【讨论】:

感谢@ypercube 的帮助!!!在我的情况下,group by 与聚合(最大)一起使用 - 你不要在“mc”上使用任何聚合......你的意思是“我完全不确定它会一直产生确定的结果”是什么意思。我看到你使用限制 & 订单 & 加入 - 丹尼尔使用最大 & 加入 - 你使用不同类型的写查询 ""JOIN name AS ON var = SELECT" 丹尼尔在他的例子中 "JOIN (SELECT) AS name =" 对我来说是如果你在 AS JOIN 上使用一些魔法 .. 等等,阅读查询会变得更加困难 :) 我看到更多图形 - 切割/创建/拆分/合并表:D - 所以很高兴看到一些图形解释这样一个复杂的查询:) 您的查询有GROUP BY message_conversationId,同时有SELECT max(message_timestamp), message_id, message_text。如果有很多行具有相同的conversationId,则返回最大时间戳。没关系。但是将返回所有message_id 中的哪一个? message_text 中的哪一个?您假设它将是具有最大时间戳的那些,但我完全不确定它是否会这样。它可能是不同的 message_id(不是最新的)和不同的文本。 是的,message_from &lt;&gt; 'me' 需要两次。 但不管有没有我在 5000 行中得到了相同的结果【参考方案2】:

好吧,这比我想象的要简单:

基本上改变选择:

max(message_timestamp)

到:

max(message_timestamp || message_id)   
or  max(message_timestamp + message_id) 

所以它会搜索时间戳和message_id的最大串联

ps。挖掘后 - 只有当消息 id 随时间戳增长时它才有效(保留插入顺序)

编辑:

编辑2:

那么为什么它有效?

SELECT max(message_timestamp+message_id), message_timestamp, message_id, message_conversationId, message_from,message_text
FROM MESSAGES
WHERE message_conversationId = 1521521
AND message_from <> 'me'
ORDER by message_Timestamp DESC

【讨论】:

时间戳上的字符串比较可能是错误的 (10 9)。 select '20' > '100' 返回真,所以连接不起作用,除非你能确保转换成字符串后的长度没有两列的长度差异。 是的,但我得到的时间戳和 message_id 一样长,那么如何添加这两个值 edit2 有效,因为时间戳是一个相对较大的数字,但请求 ID 很小。但是当请求 id 增长并且时间戳变大时,它就会出现问题,即它获得请求 id 的最大值然后时间戳。你最好防止这种情况,因为 edit2 有条件地为“真”,并且在编程上不正确。 虽然请求 id 大于时间戳的情况很少发生,因为表很少这么大【参考方案3】:

尝试下面的sql,按两次分组达到你的目的。

select m.*
from
Messages m
-- 3. and then joining to get wanted output columns
inner join
(
    --2. then selecting from this max timestamp - and removing duplicates
    select conversation_id, max(timestamp), message_id
    from
    (
        -- 1. first select max message_id in remainings after the removal of duplicates from mix of cv_id & timestamp
        select conversation_id, timestamp, max(message_id) message_id
        from Messages
        where message <> 'me'
        group by conversation_id, timestamp
    ) max_mid
    group by conversation_id
) max_mid_ts on max_mid_ts.message_id = m.message_id
order by m.message_id;

http://goo.gl/MyZjyU

【讨论】:

是的,它有效,但它与我的方法有何不同?我创建了新列,我得到了最大值(好吧,我可能理解 10 + 100 != 101 + 00 但那两个是 10100) 感谢我在 where clausule 中插入 :) 并按 .. 设置顺序,但我试图理解您的查询 如果你像字符串一样添加这些字段,问题是10||20 > 10||101 => '1020' > '10101',它最终选择了较低的消息ID。跨度> 1.首先,在从 cv_id 和时间戳的混合中删除重复项后,在剩余部分中选择 max message_id 2.然后你从这个最大时间戳中选择 - 并删除重复项

以上是关于sqlite3 按最大值查询并按第二个因素过滤的主要内容,如果未能解决你的问题,请参考以下文章

orderByChild() 如果值相同,如何按第二个变量排序?

如何按第二个单词对列表进行排序? [复制]

如何制作按第二个元素排序的最小元组堆?

按第二个值对元组列表进行排序,reverse=True,然后按 key,reverse=False

如何按第一个值和第二个值对 pair<int, char> 的向量进行排序? [复制]

有一个form,包含两个text,和两个按钮,当用户按第一个按扭时把数据提交到url1,按第二个按钮提交到url2,怎么实现呀?