修改后的问题:
我有一张桌子
CREATE TABLE my_table (id INT, type_key int, rate_1 double precision, rate_2 double precision);
INSERT INTO my_table (id, type_key, rate_1, rate_2)
VALUES
(1, NULL, 0.2, 3),
(2, 1, 1.3, 5),
(3, 1, NULL, 10),
(4, 2, 0.5, NULL),
(5, 2, 0.01, 0),
(6, 2, 0.75, NULL),
(7, 3, NULL, NULL),
(8, 3, 0.34, 1),
(9, 3, NULL, 1);
理想情况下,结果表将是:
(id, score_1, score_2)
(1, NULL, NULL),
(2, 0, 4),
(3, NULL, 3),
(4, 2, NULL),
(5, 2, 4),
(6, 3, NULL),
(7, NULL, NULL),
(8, 4, 2),
(9, NULL, 3);
基于得分阈值,如下所示:
CASE WHEN type_key = 1 THEN (
CASE
WHEN rate_1 > .7 THEN 0
WHEN rate_1 > .5 THEN 1
WHEN rate_1 > .4 THEN 2
WHEN rate_1 > .3 THEN 3
ELSE 4
(并为每个type_key_n和rate_n重复)
原始问题:
我有一个表,为简单起见,假设它有三列:date
,name
和value
。
我要基于此创建一个表,在该表中,我根据value
的大小将每个名称分类到了bins中。
现在,一种方法是写:
CREATE TABLE resulting_table AS
(SELECT DATE,
name,
CASE
WHEN value >= magnitude_1 THEN result_1
WHEN value >= magnitude_2 THEN result_2
WHEN value >= magnitude_n THEN result_n
END AS bins
FROM my_table)
但是随着n的增加,该查询将变得很长且难以辨认。而且,如果我对不同的name
具有不同的阈值幅度,那么我就必须像这样做一个嵌套的case语句:
CREATE TABLE resulting_table AS
(SELECT DATE,
CASE
WHEN name = 'name_n' THEN
CASE
WHEN value >= name_n_magnitude_n THEN result_n_n
END AS bins
FROM my_table)
这意味着查询的时间更长,可读性更差。
对于如何解决这个问题,我有两个想法,但是我不确定哪个更好,或者我将如何实现。
1)为所有name
,magnitude
和result
组合创建一个单独的表。将此表与my_table
结合使用以获得resulting_table
2)结合使用postgresql / psycopg2和python,以易于阅读的方式实现此逻辑。
这里有什么想法吗?看来这将是一个常见的数据清理/数据工程问题。
答案 0 :(得分:0)
请提供数据样本,并提供有关“ Python解决方案”或“ SQL解决方案”的更多信息。我更喜欢使用SQL解决大多数问题。这里是通用解决方案(请参见Range Types)。
关于SQL的好处也是丑陋的:它只能与表格数据一起完美地运行,没有其他数据结构...甚至类似于矩阵的东西也必须取消嵌套。因此,您的提示是正确的:“创建单独的表”。但是对于小型数据集,有一些不错的选择:数组和JSONb。让我们使用范围类型数组。
从一些教学示例开始:
SELECT '[1,10)'::int4range @> 4, '[1,10)'::int4range @> 44; -- true, false
SELECT idx, r @> 4 a, r @> 44 b
FROM unnest(array[int4range(1,10),int4range(11,50)]) WITH ORDINALITY t(r,idx);
因此,数组数据集就像一个表,具有列类型和主键。现在,您可以将此范围数组与任何其他值数组进行匹配。解决方案:
CREATE TABLE resulting_table AS
(SELECT DATE,
name,
(SELECT (array['a','b','c'])[idx] -- array of results
FROM unnest(array[int4range(1,10),int4range(11,50),int4range(51,100)])
WITH ORDINALITY t(magnitude,idx)
WHERE magnitude @> value
) AS bins
FROM my_table)
这在使用较少数组的表时更快(因为被编译为“内联函数”)。当数组需要更多〜1000个元素时,请使用EXPLAN ANALYSE。
答案 1 :(得分:0)
(第二个)已编辑问题的答案
假设每个type_key=n
存在一个rate_n
,并且
通过数组而不是孤立的值对利率建模...因此,假设表中的所有行都存在rate[type_key]
。
CREATE TABLE my_table (
id int, -- same
type_key int, -- same
rate double precision[] -- changed to array
);
INSERT INTO my_table
(id, type_key, rate)
VALUES
(1, NULL, array[0.2, 3, NULL]),
(2, 1, array[1.3, 5, NULL]),
(3, 1, array[NULL, 10, 0.2]),
(4, 2, array[0.5, NULL,0.1]),
(5, 2, array[0.01, 0, 0.02]),
(6, 2, array[0.75, NULL,0.6]),
(7, 3, array[NULL::double precision, NULL,0.1]),
(8, 3, array[0.34, 1,0.31]),
(9, 3, array[NULL, 1,0.1])
;
请更好的样品来测试解决方案...示例:
INSERT INTO my_table
(id, type_key, rate)
VALUES
(20, 1, array[0.5, 0, 0]),
(21, 1, array[0.7, 0, 0]),
(22, 2, array[0, 0.7, 0])
;
SELECT m.id, (
SELECT COALESCE( max(idx)-1, 0 )
FROM unnest(cmp[type_key:type_key]) WITH ORDINALITY tt(x,idx)
WHERE m.rate[type_key]>x
) score
FROM my_table m,
(select array[
[0.0, 0.3, 0.4, 0.5, 0.7], -- "case set" of rate_1
[0.0, 0.31, 0.4, 0.45, 0.72], -- "case set" of rate_2
[0.0, 0.22, 0.41, 0.55, 0.8] -- "case set" of rate_3
]) t(cmp)
;
结果
id | score
----+-------
1 | 0
2 | 4
3 | 0
4 | 0
5 | 0
6 | 0
7 | 0
8 | 1
9 | 0
20 | 2
21 | 3
22 | 3