我有一张桌子:
|Date |Type |MetricA|MetricB|
|01-01|House|0 |500 |
|01-01|Paid |1 |1000 |
|01-01|Paid |1 |4000 |
|02-01|House|0 |3000 |
|02-01|Paid |10 |13000 |
|02-01|House|0 |5000 |
|02-01|Paid |5 |10000 |
|02-01|Paid |1 |1500 |
我想计算第3个指标(1000 * MetricA / MetricB),我也希望MetricB按类型拆分,这样我的最终表格如下所示:
|Date |Metric_House|Metric_Paid|MetricA|NewMetric
|01-01|500 |5000 |2 |0.40
|02-01|8000 |24500 |16 |0.653061224
(我希望表结构有意义,否则我可以在这里推荐你的截图:https://i.imgur.com/5HZiMh8.png)
我想出了如何正确编写Metric_House,Metric_Paid,MetricA列,但我正在努力编写NewMetric。
有时MetricB == 0,然后我可以除以0.我可以写一个案例函数,但后来遇到聚合求和问题。我花了几个小时尝试为此写一个查询,我只是无法弄明白:( 我试过这个:
func.sum(case([((i.c.metricb) != 0, 1000*func.sum(i.c.metrica)/i.c.metricb)], else_=0))
哪个是SQLAlchemy(基于SQL的Python层),但它基本上是:
SUM(CASE WHEN METRIC != 0 THEN 1000*SUM(METRICA)/SUM(METRICB) ELSE 0
我在查询后遇到嵌套错误。
我在Python框架中工作,当我忽略查询中的NewMetric列并稍后使用简单列表函数添加它时,我在几分钟内完成了它。但我宁愿在SQL中而不是在外部处理数据。 编写此查询的最佳方法是什么?提前谢谢!
编辑:
以下是我的工作:
stmt = select([i.c.date,
cast(func.sum(case([(
i.c.type != 'House', i.c.metricb)], else_=0)),
Integer).label('metric_paid'),
cast(func.sum(case([(
i.c.type == 'House', i.c.metricb)], else_=0)),
Integer).label('metric_house'),
cast(func.sum(i.c.metrica), Float).label('metrica')]).group_by(
i.c.date).order_by(asc(i.c.date))
现在这是我尝试的(添加这个额外的表达式):
case([(sum(i.c.metricb) != 0,
1000*sum(i.c.metrica)/sum(i.c.metricb))], else_=0)])
NotImplementedError:此表达式
不支持运算符'getitem'func.sum(case([(i.c.metricb!= 0,
1000*func.sum(i.c.metrica)/func.sum(i.c.metricb))], else_=0))
(psycopg2.ProgrammingError)聚合函数调用不能嵌套LINE 1:... i.metricb!= 0)THEN(1000 * sum(i ...
更多试验和错误:
case([(and_(func.sum(i.c.metricb) != 0, (i.c.type) != 'House'), 1000*func.sum(i.c.metrica)/func.sum(i.c.metricb))])
ProgrammingError:(psycopg2.ProgrammingError)列“type”必须出现在GROUP BY子句中或用于聚合函数
但是我不希望group by子句中的type列,不会产生错误的结果
答案 0 :(得分:0)
在这里,您可以进行以下工作:
WITH mytable AS (
SELECT
*
FROM (
VALUES
('2018-01-01', 'House', 0, 500),
('2018-01-01', 'Paid', 1, 1000),
('2018-01-01', 'Paid', 1, 4000),
('2018-01-02', 'House', 0, 3000),
('2018-01-02', 'Paid', 10, 13000),
('2018-01-02', 'House', 0, 5000),
('2018-01-02', 'Paid', 5, 10000),
('2018-01-02', 'Paid', 1, 1500)
) AS t(date, type, metric_a, metric_b)
)
-- you dont need the above CTE, it is there just for testing in place of your table; use just the select below
SELECT
date,
sum(metric_b) FILTER (WHERE type = 'House') AS metric_house,
sum(metric_b) FILTER (WHERE type = 'Paid') AS metric_paid,
sum(metric_a) AS metric_a,
CASE
WHEN sum(metric_b) FILTER (WHERE type = 'Paid') > 0
THEN round(1000.0 * sum(metric_a) / sum(metric_b) FILTER (WHERE type = 'Paid'), 4)
ELSE 0
END AS new_metric
FROM mytable
GROUP BY date
ORDER BY date;
这给出了:
| date | metric_house | metric_paid | metric_a | new_metric |
|------------|--------------|-------------|----------|------------|
| 2018-01-01 | 500 | 5000 | 2 | 0.4 |
| 2018-01-02 | 8000 | 24500 | 16 | 0.6531 |
另外,您对metric_new的定义不明确。根据您发布的结果,您实际上并不想要除以整个metric_b,而只需要按"付费"部分内容。