2014-03-02 114 views
0

我有一个包含许多(+1000)列和行(〜1M)的表。列的值为1,或者为NULL。Postgresql为一行选择具有特定值的所有列和列名称

我希望能够选择,对于一个特定行(用户)检索具有的1

由于有上表中的许多列值的列名,指定列将产生一个非常长查询。

+0

你可以行转换为'hstore'对象,然后将其转换为单独的键和值数组,并只返回值为1的键。 –

+0

为什么这很奇怪?转换为稀疏矩阵时,我的表格非常宽以节省空间。 –

+0

@ManuelG这个目标很有意义,但是SQL在动态列访问方面非常糟糕。所以你节省了空间,并且交换了一个很难解决的问题。要处理这些行,你基本上必须将它们转化为键/值形式。 –

回答

0

您正在做的事情SQL在动态访问列或将一行视为集合时很糟糕。如果这更容易,它会很好,但它不适用于SQL的键入本质和关系的概念。以目前的形式处理您的数据集将会令人沮丧;考虑存储一个数组,jsonhstore的值。

实际上,对于这个特定的数据模型,你可能可以使用一个位域。见bit(n) and bit varying(n)

尽管仍然可以使用当前的PostgreSQL扩展模块进行工作查询。

鉴于样品:

CREATE TABLE blah (id serial primary key, a integer, b integer, c integer); 
INSERT INTO blah(a,b,c) VALUES (NULL, NULL, 1), (1, NULL, 1), (NULL, NULL, NULL), (1, 1, 1); 

我UNPIVOT每一行到使用hstore(或在新的PostgreSQL版本中,JSON功能)键/值集合。 SQL自身没有办法动态访问列,所以我们必须使用扩展。所以:

SELECT id, hs FROM blah, LATERAL hstore(blah) hs; 

然后提取hstore s到集:

SELECT id, k, v FROM blah, LATERAL each(hstore(blah)) kv(k,v); 

...此时您可以筛选符合标准值。请注意,所有列已转换为text,所以你可能想将它转换回:

SELECT id, k FROM blah, LATERAL each(hstore(blah)) kv(k,v) WHERE v::integer = 1; 

您还需要从配套排除id,所以:

regress=> SELECT id, k FROM blah, LATERAL each(hstore(blah)) kv(k,v) WHERE v::integer = 1 AND 
k <> 'id'; 
id | k 
----+--- 
    1 | c 
    2 | a 
    2 | c 
    4 | a 
    4 | b 
    4 | c 
(6 rows) 
相关问题