如何将长字符串标识符唯一映射到单个查询中的数值(出于带宽原因)?

时间:2016-04-26 20:41:19

标签: postgresql greenplum

我有一个Postgresql数据库(技术上是Greenplum),随着时间的推移,有关于个人的数据。该数据库有三个字段:user_idmonthly_dateaccount_value。当我提出查询时,我必须从远程服务器下载结果,因此带宽是个问题。由于user_id字段是一个非常长的字符串(大约50个字符),因此我希望返回一个与user_id的每个值对应1:1的数值,因为这将占用更少的空间。

例如,数据库可能包含以下示例数据:

63a9364385350b13473279    Jan-2000
63a9364385350b13473279    Feb-2000
2066937e2887w206010393    Apr-2001
036686037e507d01764237    Mar-2003
036686037e507d01764237    Jun-2003
036686037e507d01764237    Jul-2003
036686037e507d01764237    Dec-2003
90829x098327549n286418    Apr-2004
90829x098327549n286418    Sep-2004
67518x834512306933u500    Nov-2000

我尝试使用ROW_NUMBER()和各种窗口函数(例如PARTITION BY)来计算查询,以获得这样的结果:

1    Jan-2000
1    Feb-2000
2    Apr-2001
3    Mar-2003
3    Jun-2003
3    Jul-2003
3    Dec-2003
4    Apr-2004
4    Sep-2004
5    Nov-2000

我知道这些不是真正的数据库格式,但我只是将它们用作示例数据。这可能吗?如果63a9364385350b13473279在一个查询中映射到1而在下一个查询中映射到2,我就不在乎(虽然它会很好并且非常简洁)在任何给定的查询中,无论日期如何,63a9364385350b13473279都应始终映射到相同的值。除了唯一之外,映射的数字不需要按顺序排列或具有任何有意义的值。

3 个答案:

答案 0 :(得分:1)

如果你只需要一个唯一的号码,这就可以解决问题:

SELECT
        id,
        split_part(t.d, '-', 2),
        row_number() OVER all_window - row_number() OVER group_window AS a_unique_number_by_id
FROM (
VALUES
        ('63a9364385350b13473279','Jan-2000'),
        ('63a9364385350b13473279','Feb-2000'),
        ('2066937e2887w206010393','Apr-2001'),
        ('036686037e507d01764237','Mar-2003'),
        ('036686037e507d01764237','Jun-2003'),
        ('036686037e507d01764237','Jul-2003'),
        ('036686037e507d01764237','Dec-2003'),
        ('90829x098327549n286418','Apr-2004'),
        ('90829x098327549n286418','Sep-2004'),
        ('67518x834512306933u500','Nov-2000')
) as t(id, d)
WINDOW group_window AS (
        PARTITION BY id
        ORDER BY split_part(t.d, '-', 2)
), all_window AS (
        ORDER BY split_part(t.d, '-', 2)
);

结果如下:

           id           | split_part | a_unique_number_by_id
------------------------+------------+-----------------------
 63a9364385350b13473279 | 2000       |                     0
 63a9364385350b13473279 | 2000       |                     0
 67518x834512306933u500 | 2000       |                     2
 2066937e2887w206010393 | 2001       |                     3
 036686037e507d01764237 | 2003       |                     4
 036686037e507d01764237 | 2003       |                     4
 036686037e507d01764237 | 2003       |                     4
 036686037e507d01764237 | 2003       |                     4
 90829x098327549n286418 | 2004       |                     8
 90829x098327549n286418 | 2004       |                     8
(10 rows)

您应该使用其他列重新排序,以保持原始排序。

答案 1 :(得分:1)

我认为你正在寻找dense_rank()。

create table sample_data
(userid varchar(50) not null,
 monthly_date date not null)
distributed by (userid);

insert into sample_data (userid, monthly_date) values 
('63a9364385350b13473279','2000-01-01'),
('63a9364385350b13473279','2000-02-01'),
('2066937e2887w206010393','2001-04-01'),
('036686037e507d01764237','2003-03-01'),
('036686037e507d01764237','2003-06-01'),
('036686037e507d01764237','2003-07-01'),
('036686037e507d01764237','2003-12-01'),
('90829x098327549n286418','2004-04-01'),
('90829x098327549n286418','2004-09-01'),
('67518x834512306933u500','2000-11-01');

select dense_rank() over(order by userid) as new_userid, userid, monthly_date 
from sample_data
order by 2;

 new_userid |         userid         | monthly_date 
------------+------------------------+--------------
      1     | 036686037e507d01764237 | 2003-06-01
      1     | 036686037e507d01764237 | 2003-07-01
      1     | 036686037e507d01764237 | 2003-12-01
      1     | 036686037e507d01764237 | 2003-03-01
      2     | 2066937e2887w206010393 | 2001-04-01
      3     | 63a9364385350b13473279 | 2000-02-01
      3     | 63a9364385350b13473279 | 2000-01-01
      4     | 67518x834512306933u500 | 2000-11-01
      5     | 90829x098327549n286418 | 2004-09-01
      5     | 90829x098327549n286418 | 2004-04-01
(10 rows)

答案 2 :(得分:-1)

尝试以下脚本

create table test_schema.source_data (id varchar(50), dt varchar(50));

insert into test_schema.source_data
values ('63a9364385350b13473279','Jan-2000'),
    ('63a9364385350b13473279','Feb-2000'),
    ('2066937e2887w206010393','Apr-2001'),
    ('036686037e507d01764237','Mar-2003'),
    ('036686037e507d01764237','Jun-2003'),
    ('036686037e507d01764237','Jul-2003'),
    ('036686037e507d01764237','Dec-2003'),
    ('90829x098327549n286418','Apr-2004'),
    ('90829x098327549n286418','Sep-2004'),
    ('67518x834512306933u500','Nov-2000');


create temporary table id_mapping
as 
select t1.id, row_number() over(order by t1.id) rownum
from (
SELECT distinct id
FROM test_schema.source_data
 ) t1;

select t1.id, t1.dt, t2.rownum
from
test_schema.source_data t1
join id_mapping t2
on t1.id = t2.id;

这是结果

id                      dt          rownum
------------------------+------------+-----
036686037e507d01764237  Dec-2003    1
036686037e507d01764237  Jul-2003    1
036686037e507d01764237  Jun-2003    1
036686037e507d01764237  Mar-2003    1
2066937e2887w206010393  Apr-2001    2
63a9364385350b13473279  Feb-2000    3
63a9364385350b13473279  Jan-2000    3
67518x834512306933u500  Nov-2000    4
90829x098327549n286418  Sep-2004    5
90829x098327549n286418  Apr-2004    5