在Django ORM中选择最近的行并进行分组

时间:2017-03-08 10:54:58

标签: django group-by

我们有一个用Django编写的系统来跟踪招募到临床试验的患者。 传播表用于记录整个财政年度每个月招募的患者数量;因此,即使研究可能会持续多年,该表仅包含12个月的数据。

django数据库中有一个表,每个月都会导入电子表格。数据包括月/年,患者数和其他一些领域。每次导入都将包括前几个月的所有数据;我们需要这样做以确保自上次导入后导入表上没有更改数据。

例如,包含两个导入的导入表(第一个截至1月,第二个截至2月)将如下所示:

 id | study_id | data_date  | patient_count | [other fields] -->
100       5456   2016-04-01              10        ...
101       5456   2016-05-01               8        ...
102       5456   2016-06-01               5        ...
   ... all months in between ...
109       5456   2016-01-01              12        ...
110       5456   2016-02-01            NULL        ...
111       5456   2016-03-01            NULL        ...
112       5456   2016-04-01              10        ...
113       5456   2016-05-01               8        ...
114       5456   2016-06-01               5        ...
   ... all months in between ...
121       5456   2016-01-01              12        ...
122       5456   2016-02-01               6        ...
123       5456   2016-03-01            NULL        ...

其他字段包含另一个包含实际研究标识号(iras_number)的表的外键,因此我必须加入其中以选择特定研究的行。

我希望研究中data_datepatient_count的最新值可能超过一个财政年度,因此我尝试了此查询(iras_number传递给该函数执行此查询):

totals = ImportStudyData.objects.values('data_date', 'patient_count') \
         .filter(import_study__iras_number=iras_number) \
         .annotate(max_id=Max('id')).order_by()

但是,这会产生一个SQL查询,其patient_count中包含GROUP BY,导致重复的行:

data_date  | patient_count | max_id
2016-04-01              10      100
2016-04-01              10      112
2016-05-01               8      101
2016-05-01               8      113
   ...
2016-01-01              12      109
2016-01-01              12      121
2016-02-01            NULL      110
2016-02-01               6      122

如何使用ORM从表格中选择最新的data_datepatient_count

如果我正在编写SQL,我会根据max(id)data_date进行内部选择,然后使用它来加入或使用IN查询来选择字段我从桌子上要求;如:

SELECT data_date, patient_count
FROM importstudydata
WHERE id IN (
    SELECT MAX(id) AS "max_id" 
    FROM importstudydata INNER JOIN importstudy
        ON importstudydata.import_study_id = importstudy.id 
    WHERE importstudy.iras_number = 5456 
    GROUP BY importstudydata.data_date
)
ORDER BY data_date ASC

我尝试创建内部选择来复制SQL查询,但内部选择返回多个字段(列)a会导致查询失败:

totals = ImportStudyData.objects.values('data_date', 'patient_count') \
         .filter(id__in=ImportStudyData.objects.values('data_date') \
                        .filter(import_study__iras_number=iras_number) \ 
                        .annotate(max_data_id=Max('id'))

现在我无法让内部选择仅返回由{data_date'分组的max(id)。并且它可以在单个SQL查询中执行。

2 个答案:

答案 0 :(得分:0)

现在我将查询分成若干步骤以获得我想要的结果。

首先,我查询与研究相关的所有行的最新id

id_qry = ImportStudyData.objects.values('data_date')\
    .filter(import_study__iras_number=iras_number)\
    .annotate(max_id=Max('id'))

为了获得仅列出数字的列表,删除日期,我使用列表理解:

id_list = [x['max_id'] for x in id_qry]

然后将此列表用作最终查询的过滤器以获取患者数量

totals = ImportStudyData.objects.values('data_date', 'patient_count') \
        .filter(id__in=id_list)

它击中了数据库两次,并且在计算上更加昂贵,但是现在它起作用了,我需要继续前进。

我稍后会回到这个问题。

答案 1 :(得分:-1)

使用:distinct = True

totals = ImportStudyData.objects.values('data_date', 'patient_count').filter(import_study__iras_number=iras_number).annotate(max_id=Max('id')).order_by('data_date').distinct()