返回列名和不同的值

时间:2015-12-16 18:44:04

标签: sql postgresql distinct set-returning-functions

假设我在postgres中有一个简单的表格如下:

+--------+--------+----------+
|  Car   |  Pet   |   Name   |
+--------+--------+----------+
| BMW    |  Dog   |   Sam    |
| Honda  |  Cat   |   Mary   |
| Toyota |  Dog   |   Sam    |
| ...    |  ...   |   ...    |

我想运行一个sql查询,它可以返回第一列中的列名和第二列中的唯一值。例如:

+--------+--------+
|  Col   |  Vals  |
+--------+--------+
| Car    |  BMW   |
| Car    | Toyota |
| Car    | Honda  |
| Pet    |  Dog   |
| Pet    |  Cat   |
| Name   |  Sam   |
| Name   |  Mary  |
| ...    |  ...   |

I found a bit of code that can be used to return all of the unique values from multiple fields into one column

-- Query 4b.  (104 ms, 128 ms)
select distinct unnest( array_agg(a)||
                        array_agg(b)||
                        array_agg(c)||
                        array_agg(d) )
from t ;

但我不太了解代码,知道如何将列名追加到另一列中。

I also found a query that can return the column names in a table.可能是上面显示的“查询4b”的子查询?

3 个答案:

答案 0 :(得分:4)

SQL Fiddle

SELECT distinct
       unnest(array['car', 'pet', 'name']) AS col,
       unnest(array[car, pet, name]) AS vals
FROM t
order by col

答案 1 :(得分:2)

将设置返回函数放在SELECT列表中并且SQL标准中不允许这样做的风格很糟糕。 Postgres支持它的历史原因,但自LATERAL引入Postgres 9.3后,它已经基本上过时了。我们也可以在这里使用它:

SELECT x.col, x.val
FROM   tbl, LATERAL (VALUES ('car', car)
                          , ('pet', pet)
                          , ('name', name)) x(col, val)
GROUP  BY 1, 2
ORDER  BY 1, 2;

您会在the very same question on dba.SE you already found yourself下找到这种LATERAL (VALUES ...)技术。只是不要在第一个答案时停止阅读。

直到Postgres 9.4 还有一个例外:" parallel unnest"需要在SELECT列表中组合多个集合返回函数。 Postgres 9.4带来了new variant of unnest()来消除这种必要性。更多:

如果返回行的数量对于SELECT列表中的所有set-returns函数不应完全相同,则新函数也不会脱轨成笛卡尔积,这是一种非常奇怪的行为。新语法变体应优先于现在过时的变体:

SELECT DISTINCT x.*
FROM   tbl t, unnest('{car, pet, name}'::text[]
                   , ARRAY[t.car, t.pet, t.name]) AS x(col, val)
ORDER  BY 1, 2;

也比两个unnest()并行呼叫更短,更快。

返回:

 col  |  val
------+--------
 car  | BMW
 car  | Honda
 car  | Toyota
 name | Mary
 name | Sam
 pet  | Cat
 pet  | Dog

DISTINCTGROUP BY,对任务都有好处。

答案 2 :(得分:1)

JSON functions row_to_json()json_each_text()您无法指定列的数量和名称:

select distinct key as col, value as vals
from (
    select row_to_json(t) r
    from a_table t
    ) t,
    json_each_text(r)
order by 1, 2;

SqlFiddle