术语:msisdn =电话号码
首先,我想为这些名字道歉。此数据库模式是使用squeryl ORM创建的,它有一些有趣的表定义选择。我在下面列出了两个相关表格。
基本上,记录包含配置请求。供应是对该记录的每次尝试。有些记录会多次尝试。
create table "Provisioning" (
"record_id" bigint not null,
"responseCode" varchar(128),
"response" varchar(128),
"id" bigint primary key not null,
"status" integer not null,
"actionRequired" boolean not null
);
create sequence "s_Provisioning_id";
create table "Record" (
"source" varchar(128) not null,
"timestamp" varchar(128) not null,
"finalState" varchar(128) not null,
"fromMSISDN" varchar(128) not null,
"reason" varchar(128) not null,
"id" bigint primary key not null,
"toICCID" varchar(128) not null,
"fromICCID" varchar(128) not null,
"toMSISDN" varchar(128) not null,
"batch_id" bigint not null,
"action" varchar(128) not null,
"transactionId" varchar(128) not null
);
我意识到配置没有时间戳。是的,最新的id是最新的请求。处理它的开发人员忘记输入时间戳,项目经理说服他们这不是原始要求的一部分,然后客户端不想支付以后添加它。不,我不高兴。不,我无能为力。是的,我讨厌为一家咨询公司工作。继续前进。
问题:我需要一份报告,告诉我每个电话号码的最新状态(msisdn)。每个电话号码可以有多个记录。在from / toMSISDN的情况下,除非它是空的,否则应始终使用toMSISDN,在这种情况下使用from。以下查询获取记录中的所有唯一电话号码:
SELECT
CASE
WHEN "toMSISDN" = '' OR "toMSISDN" IS NULL THEN "fromMSISDN"
ELSE "toMSISDN"
END AS msisdn
FROM "Record"
GROUP BY msisdn
因此,这给了我需要报告的所有数字的子集。现在我需要最新的Record和Provisioing。我可以使用以下内容获取最新的Provisiong:
SELECT
max(p.id) latest_provision_id,
p.record_id
FROM "Provisioning" p
LEFT JOIN "Record" r ON r.id = p.record_id
group by p.record_id
因此,这给了我每个记录的1对1表以及它最新的配置。这就是我开始陷入困境的地方。在Provisioning表中,我需要最新Provisioing的响应和响应代码。我想到只是将max(p。“responseCode”)添加到查询中,但后来我意识到它很可能会进行字母比较,而不是为相应的Provisioning.id获取正确的responseCode /响应。我尝试将这些字段添加到Group By,但后来我开始在查询中获得额外的记录,我不太确定发生了什么。
这个(非常丑陋的子查询连接)似乎给了我正确的记录行和配置行信息,但它是永远的记录,我需要为每个msisdn /电话号码(计算字段)获取最新的(最大配置ID) 。我不确定要分组的内容以及要使用的聚合函数。
SELECT *,
CASE
WHEN "toMSISDN" = '' OR "toMSISDN" IS NULL THEN "fromMSISDN"
ELSE "toMSISDN"
END AS msisdn
FROM (
SELECT
max(p.id) latest_provision_id,
p.record_id
FROM "Provisioning" p
LEFT JOIN "Record" r ON r.id = p.record_id
group by p.record_id
) latest_prov
LEFT JOIN "Provisioning" p2 ON p2.id=latest_prov.latest_provision_id
LEFT JOIN "Record" r2 ON r2.id=latest_prov.record_id
如果不运行多个查询并在应用程序层中处理结果,我似乎无法想到这样做的干净方法。
我原本打算使用相同的squeryl ORM作为Scala应用程序执行此操作,但查询变得相当复杂,我停止了以下语句,而是选择将报告作为Python应用程序执行:
def getSimSnapshot() = {
join(record,provisioning.leftOuter)((r,p) =>
groupBy(r.fromMSISDN)
compute(max(r.id),r.finalState,r.fromMSISDN,r.reason,r.action)
on(r.id === p.map(_.record_id))
)
}
如果使用ORM有一种更简单的方法,我会全力以赴。
答案 0 :(得分:2)
查看窗口函数:http://www.postgresql.org/docs/8.4/static/tutorial-window.html
如果没有联接,您可以获取record_id的最新数据:
select *
from
(
select p.record_id, p.responseCode, p.id, max(p.id) over (partition by p.record_id) max_id
from "Provisioning" p
)
where id = max_id
仅当“Provisioning”还包含不同表的record_id然后“Records”
时,它才会出现问题