过滤具有相邻ID的SQL元素

时间:2018-09-22 18:52:55

标签: python sql django postgresql django-models

我真的不知道如何在标题中正确陈述这个问题。

假设我有一个Word表,如下所示:

| id  | text   |
| --- | ---    |
|  0  | Hello  |
|  1  | Adam   |
|  2  | Hello  |
|  3  | Max    |
|  4  | foo    |
|  5  | bar    |

是否可以基于text查询该表并接收主键(id)恰好为一的对象?

所以,如果我这样做

Word.objects.filter(text='Hello')

我得到一个包含行的QuerySet

| id  | text   |
| --- | ---    |
|  0  | Hello  |
|  2  | Hello  |

但是我想要行

| id  | text   |
| --- | ---    |
|  1  | Adam   |
|  3  | Max    |

我想我能做

word_ids = Word.objects.filter(text='Hello').values_list('id', flat=True)
word_ids = [w_id + 1 for w_id in word_ids]  # or use a numpy array for this
Word.objects.filter(id__in=word_ids)

但这似乎并不太有效。有一个简单的SQL方法可以在一次调用中做到这一点吗?最好直接使用Django的QuerySet?

编辑:这个想法是,实际上我想过滤第二个QuerySet中的那些单词。像这样:

Word.objects.filter(text__of__previous__word='Hello', text='Max')

2 个答案:

答案 0 :(得分:2)

在普通的Postgres中,您可以使用lag窗口函数(https://www.postgresql.org/docs/current/static/functions-window.html

SELECT 
    id, 
    name 
FROM (
    SELECT 
        *, 
        lag(name) OVER (ORDER BY id) as prev_name
    FROM test
) s
WHERE prev_name = 'Hello'

lag函数添加带有上一行文本的列。因此,您可以在子查询中按此文本进行过滤。

demo:db<>fiddle


我不是真的很喜欢Django,但是documentation意味着,在2.0版中,已添加了窗口功能。

答案 1 :(得分:1)

如果“ 1 off”表示差异正好是1,则可以执行以下操作:

select w.*
from w
where w.id in (select w2.id + 1 from words w2 where w2.text = 'Hello');

lag()也是一个非常合理的解决方案。这似乎是您问题的直接解释。如果您有差距(意图是+ 1),那么lag()会比较棘手。