合并两个 QuerySets 或重新排序一个 QS,使得每个第 n 个元素都来自第二个
Merge two QuerySets or reorder one QS such that every n-th element will be from the second one
我不确定这是否可以仅使用 Django
ORM
或纯 SQL
来完成。我有一个模型 Fruit
,我想渲染一个水果列表,使得第 n 个水果都是 type="apple"
。
所以 4 将是:
- 苹果以外的任何水果
- 苹果以外的任何水果
- 苹果以外的任何水果
- 苹果
- 苹果以外的任何水果
- 除苹果外的任何水果
...
我正在寻找一种比一大堆水果更有效的方法,最好是一个 QuerySet
但不确定是否可行。
fruits_except_apples = Fruit.objects.exclude(type='apple')
apples = Fruit.objects.filter(type='apple')
我什至可以创建两个 QuerySets
,然后以某种方式合并它们,或者只是重新排序一个 QuerySet
。
我不知道它是否有帮助,但此查询以您的方式订购水果。但我相信这可以以更有效的方式在循环(SQL 函数或 python)中完成。
SELECT
name, type
FROM (
SELECT
name, type,
row_number + (row_number - 1) / 3 as row_number
FROM (
SELECT
*,
row_number() OVER ()
FROM fruits
WHERE type != 'apple'
)s
UNION
SELECT
*,
4 * row_number() OVER ()
FROM fruits
WHERE type = 'apple'
) s
ORDER BY row_number
分步说明:
主要问题是获得具有两种不同行数的订单:一种是步数为 4 (4, 8, 12, ...) 另一种步数为 1 但没有步数为 4 (1,2 ,3,5,6,7,9,...), 这才是真正的问题。
我的table:
| name | type |
|------|-----------|
| A1 | apple |
| A2 | apple |
| A3 | apple |
| B1 | banana |
| B2 | banana |
| B3 | banana |
| B4 | banana |
| O1 | orange |
| K1 | kiwi |
| K2 | kiwi |
| K3 | kiwi |
| C1 | chocolate |
| C2 | chocolate |
第一部分。获取非苹果订单:
使用 window function row_number
。这会在数据中添加一个行计数列:
SELECT
*,
row_number() OVER ()
FROM fruits
WHERE type != 'apple'
name type row_number
---- --------- ----------
B1 banana 1
B2 banana 2
B3 banana 3
B4 banana 4
O1 orange 5
K1 kiwi 6
K2 kiwi 7
K3 kiwi 8
C1 chocolate 9
C2 chocolate 10
现在我们必须创造差距。为此,有必要移动 3 个块:ids 4、5、6 应变为 5、6、7; ids 7,8,9 应该变成 9,10,11 等等。
3的块可以通过在下一个子选择中row_number
的整数除法来实现:
SELECT
*,
row_number / 3
FROM (
SELECT
*,
row_number() OVER ()
FROM fruits
WHERE type != 'apple'
)s
这给出了
name type row_number ?column?
---- --------- ---------- --------
B1 banana 1 0
B2 banana 2 0
B3 banana 3 1
B4 banana 4 1
O1 orange 5 1
K1 kiwi 6 2
K2 kiwi 7 2
K3 kiwi 8 2
C1 chocolate 9 3
C2 chocolate 10 3
我们可以看到简单的除法还是移位了。因此,减去 1 我们得到了我们期望的结果:
SELECT
*,
(row_number - 1) / 3
FROM (
SELECT
*,
row_number() OVER ()
FROM fruits
WHERE type != 'apple'
)s
这给出了
name type row_number ?column?
---- --------- ---------- --------
B1 banana 1 0
B2 banana 2 0
B3 banana 3 0
B4 banana 4 1
O1 orange 5 1
K1 kiwi 6 1
K2 kiwi 7 2
K3 kiwi 8 2
C1 chocolate 9 2
C2 chocolate 10 3
现在我们可以看到我们可以添加最右边的两列来实现我们的结果:
SELECT
*,
(row_number - 1) / 3 + row_number
FROM (
SELECT
*,
row_number() OVER ()
FROM fruits
WHERE type != 'apple'
)s
这给出了
name type row_number ?column?
---- --------- ---------- --------
B1 banana 1 1
B2 banana 2 2
B3 banana 3 3
B4 banana 4 5
O1 orange 5 6
K1 kiwi 6 7
K2 kiwi 7 9
K3 kiwi 8 10
C1 chocolate 9 11
C2 chocolate 10 13
要获得 apple
id,我们只需再次使用 row_number()
函数,它枚举 apple
行(1,2,3,...)。然后我们简单地将这些id乘以4得到(4,8,12,...).
两个部分都可以通过 UNION
连接起来,然后必须按它们生成的 ID 进行排序。
我不确定这是否可以仅使用 Django
ORM
或纯 SQL
来完成。我有一个模型 Fruit
,我想渲染一个水果列表,使得第 n 个水果都是 type="apple"
。
所以 4 将是:
- 苹果以外的任何水果
- 苹果以外的任何水果
- 苹果以外的任何水果
- 苹果
- 苹果以外的任何水果
- 除苹果外的任何水果 ...
我正在寻找一种比一大堆水果更有效的方法,最好是一个 QuerySet
但不确定是否可行。
fruits_except_apples = Fruit.objects.exclude(type='apple')
apples = Fruit.objects.filter(type='apple')
我什至可以创建两个 QuerySets
,然后以某种方式合并它们,或者只是重新排序一个 QuerySet
。
我不知道它是否有帮助,但此查询以您的方式订购水果。但我相信这可以以更有效的方式在循环(SQL 函数或 python)中完成。
SELECT
name, type
FROM (
SELECT
name, type,
row_number + (row_number - 1) / 3 as row_number
FROM (
SELECT
*,
row_number() OVER ()
FROM fruits
WHERE type != 'apple'
)s
UNION
SELECT
*,
4 * row_number() OVER ()
FROM fruits
WHERE type = 'apple'
) s
ORDER BY row_number
分步说明:
主要问题是获得具有两种不同行数的订单:一种是步数为 4 (4, 8, 12, ...) 另一种步数为 1 但没有步数为 4 (1,2 ,3,5,6,7,9,...), 这才是真正的问题。
我的table:
| name | type |
|------|-----------|
| A1 | apple |
| A2 | apple |
| A3 | apple |
| B1 | banana |
| B2 | banana |
| B3 | banana |
| B4 | banana |
| O1 | orange |
| K1 | kiwi |
| K2 | kiwi |
| K3 | kiwi |
| C1 | chocolate |
| C2 | chocolate |
第一部分。获取非苹果订单:
使用 window function row_number
。这会在数据中添加一个行计数列:
SELECT
*,
row_number() OVER ()
FROM fruits
WHERE type != 'apple'
name type row_number
---- --------- ----------
B1 banana 1
B2 banana 2
B3 banana 3
B4 banana 4
O1 orange 5
K1 kiwi 6
K2 kiwi 7
K3 kiwi 8
C1 chocolate 9
C2 chocolate 10
现在我们必须创造差距。为此,有必要移动 3 个块:ids 4、5、6 应变为 5、6、7; ids 7,8,9 应该变成 9,10,11 等等。
3的块可以通过在下一个子选择中row_number
的整数除法来实现:
SELECT
*,
row_number / 3
FROM (
SELECT
*,
row_number() OVER ()
FROM fruits
WHERE type != 'apple'
)s
这给出了
name type row_number ?column?
---- --------- ---------- --------
B1 banana 1 0
B2 banana 2 0
B3 banana 3 1
B4 banana 4 1
O1 orange 5 1
K1 kiwi 6 2
K2 kiwi 7 2
K3 kiwi 8 2
C1 chocolate 9 3
C2 chocolate 10 3
我们可以看到简单的除法还是移位了。因此,减去 1 我们得到了我们期望的结果:
SELECT
*,
(row_number - 1) / 3
FROM (
SELECT
*,
row_number() OVER ()
FROM fruits
WHERE type != 'apple'
)s
这给出了
name type row_number ?column?
---- --------- ---------- --------
B1 banana 1 0
B2 banana 2 0
B3 banana 3 0
B4 banana 4 1
O1 orange 5 1
K1 kiwi 6 1
K2 kiwi 7 2
K3 kiwi 8 2
C1 chocolate 9 2
C2 chocolate 10 3
现在我们可以看到我们可以添加最右边的两列来实现我们的结果:
SELECT
*,
(row_number - 1) / 3 + row_number
FROM (
SELECT
*,
row_number() OVER ()
FROM fruits
WHERE type != 'apple'
)s
这给出了
name type row_number ?column?
---- --------- ---------- --------
B1 banana 1 1
B2 banana 2 2
B3 banana 3 3
B4 banana 4 5
O1 orange 5 6
K1 kiwi 6 7
K2 kiwi 7 9
K3 kiwi 8 10
C1 chocolate 9 11
C2 chocolate 10 13
要获得 apple
id,我们只需再次使用 row_number()
函数,它枚举 apple
行(1,2,3,...)。然后我们简单地将这些id乘以4得到(4,8,12,...).
两个部分都可以通过 UNION
连接起来,然后必须按它们生成的 ID 进行排序。