sql 查询的查询集
Queryset for a sql query
有关问题描述、示例数据和 postgres 查询,请参阅 。我想将 SQL 转换为查询集。我觉得我很接近但又不完全。
SELECT Column_A, Column_B, Column_C, 0 as RN
FROM TABLE
WHERE COLUMN_C is null and Column_B in (UserA, UserB, UserC)
UNION ALL
SELECT Column_A, Column_B, Column_C, RN
FROM (
SELECT A.*, ROW_NUMBER() over (partition by A.column_C Order by case A.column_B when 'UserA' then 0 else 1 end, U.Time_Created) rn
FROM Table A
INNER JOIN user U
on U.Column_B = A.Column_B
WHERE A.Column_C is not null and ColumnB in (userA, userB, UserC)) B
WHERE RN = 1
这是我目前拥有的:
qs1 = Table.objects.filter(Column_C__isnull=True).annotate(rn=Value(0))
qs2 = Table.objects.annotate(rn=Window(
expression=RowNumber(),
partition_by=[Column_C],
order_by=[Case(When(Column_B=UserA, then=0), default=1), 'Table_for_Column_B__time_created']
)).filter(Column_C__isnull=False, rn=1)
return qs2.union(qs1)
这不太行。
django.db.utils.NotSupportedError: Window is disallowed in the filter clause.
接下来,我尝试在子查询中提取中间结果,以允许在外部查询中进行过滤,因为我真的只需要行号 = 1 的行。
qs1 = Table.objects.filter(Column_C__isnull=True).annotate(rn=Value(0))
qs2 = Table.objects.annotate(rn=Window(
expression=RowNumber(),
partition_by=[Column_C],
order_by=[Case(When(Column_B=UserA, then=0), default=1), 'Table_for_Column_B__time_created']
)).filter(pk=OuterRef('pk'))
qs3 = Table.objects.annotate(rn=Subquery(qs2.values('rn'))).filter(Column_C__isnull=False, rn=1)
return qs3.union(q1)
这次没有例外,但这行不通。 table 中的每一行都带有 row_number=1 注释。从原始示例中,查询集 returns 所有 7 行而不是过滤到 5.
- 是否可以过滤 window 表达式?
- 将 window 查询转换为子查询时要记住的最佳做法是什么?
- 有没有更好的方法来构建查询集?
你应该可以不用 window 表达式,使用 SubQuery
首先为按 Column_B=UserA
匹配排序的子查询创建一个查询集,然后 time_created
from django.db.models import Case, When, Q, Subquery, OuterRef
tables_ordered = Table.objects.filter(
Column_C=OuterRef('Column_C')
).annotate(
user_match=Case(When(Column_B=UserA, then=0), default=1)
).order_by('user_match', 'time_created')
然后此子查询 returns 来自 OuterRef
的匹配 Column_C
的第一个 pk,类似于从 window 函数中选择第一行
first_pk_for_each_column_c = Subquery(tables_ordered.values('pk')[:1])
然后使用两个 Q objects to create an OR 选择行,如果 Column_C
为 NULL 或者 pk
匹配子查询
中的第一个 pk
Table.objects.filter(
Q(Column_C__isnull=True) | Q(pk=first_pk_for_each_column_c)
)
有关问题描述、示例数据和 postgres 查询,请参阅
SELECT Column_A, Column_B, Column_C, 0 as RN
FROM TABLE
WHERE COLUMN_C is null and Column_B in (UserA, UserB, UserC)
UNION ALL
SELECT Column_A, Column_B, Column_C, RN
FROM (
SELECT A.*, ROW_NUMBER() over (partition by A.column_C Order by case A.column_B when 'UserA' then 0 else 1 end, U.Time_Created) rn
FROM Table A
INNER JOIN user U
on U.Column_B = A.Column_B
WHERE A.Column_C is not null and ColumnB in (userA, userB, UserC)) B
WHERE RN = 1
这是我目前拥有的:
qs1 = Table.objects.filter(Column_C__isnull=True).annotate(rn=Value(0))
qs2 = Table.objects.annotate(rn=Window(
expression=RowNumber(),
partition_by=[Column_C],
order_by=[Case(When(Column_B=UserA, then=0), default=1), 'Table_for_Column_B__time_created']
)).filter(Column_C__isnull=False, rn=1)
return qs2.union(qs1)
这不太行。
django.db.utils.NotSupportedError: Window is disallowed in the filter clause.
接下来,我尝试在子查询中提取中间结果,以允许在外部查询中进行过滤,因为我真的只需要行号 = 1 的行。
qs1 = Table.objects.filter(Column_C__isnull=True).annotate(rn=Value(0))
qs2 = Table.objects.annotate(rn=Window(
expression=RowNumber(),
partition_by=[Column_C],
order_by=[Case(When(Column_B=UserA, then=0), default=1), 'Table_for_Column_B__time_created']
)).filter(pk=OuterRef('pk'))
qs3 = Table.objects.annotate(rn=Subquery(qs2.values('rn'))).filter(Column_C__isnull=False, rn=1)
return qs3.union(q1)
这次没有例外,但这行不通。 table 中的每一行都带有 row_number=1 注释。从原始示例中,查询集 returns 所有 7 行而不是过滤到 5.
- 是否可以过滤 window 表达式?
- 将 window 查询转换为子查询时要记住的最佳做法是什么?
- 有没有更好的方法来构建查询集?
你应该可以不用 window 表达式,使用 SubQuery
首先为按 Column_B=UserA
匹配排序的子查询创建一个查询集,然后 time_created
from django.db.models import Case, When, Q, Subquery, OuterRef
tables_ordered = Table.objects.filter(
Column_C=OuterRef('Column_C')
).annotate(
user_match=Case(When(Column_B=UserA, then=0), default=1)
).order_by('user_match', 'time_created')
然后此子查询 returns 来自 OuterRef
的匹配 Column_C
的第一个 pk,类似于从 window 函数中选择第一行
first_pk_for_each_column_c = Subquery(tables_ordered.values('pk')[:1])
然后使用两个 Q objects to create an OR 选择行,如果 Column_C
为 NULL 或者 pk
匹配子查询
pk
Table.objects.filter(
Q(Column_C__isnull=True) | Q(pk=first_pk_for_each_column_c)
)