Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 从查询数据创建列_Sql_Postgresql_Crosstab - Fatal编程技术网

Sql 从查询数据创建列

Sql 从查询数据创建列,sql,postgresql,crosstab,Sql,Postgresql,Crosstab,测试数据: create temp table l (id integer,name text); create temp table t (id integer); create temp table t_i18n(id integer,l_id integer,t_id integer,name text); insert into l(id, name) values (1, 'lang_1'), (2, 'lang_2'); insert into t(id) values(1); in

测试数据:

create temp table l (id integer,name text);
create temp table t (id integer);
create temp table t_i18n(id integer,l_id integer,t_id integer,name text);
insert into l(id, name) values
(1, 'lang_1'),
(2, 'lang_2');
insert into t(id) values(1);
insert into t_i18n(id, l_id, t_id, name) values 
(1, 1, 1, 'Text in the language one'),
(2, 2, 1, 'Text in the language two');
执行此查询后:

select *
from t
inner join t_i18n i18n
on i18n.t_id = t.id;
select  t1.id,    
        i18n1.l_id l_id1,
        i18n1.t_id t_id1,
        i18n1.name name1,
        i18n2.l_id l_id2,
        i18n2.t_id t_id2,
        i18n2.name name2
from t t1
left join t_i18n i18n1 on i18n1.t_id = t1.id and i18n1.l_id = 1
full outer join t t2 on t1.id = t2.id
left join t_i18n i18n2 on i18n2.t_id = t2.id and i18n2.l_id = 2
我有一个结果:

 id | id | l_id | t_id |           name           
----+----+------+------+--------------------------
  1 |  1 |    1 |    1 | Text in the language one  
  1 |  2 |    2 |    1 | Text in the language two
是否可以修改上面的查询以获得下面的结果

/*Expected result*/
 id | name_lang_1              | name_lang_2
----+--------------------------+--------------------------
  1 | Text in the language one | Text in the language two
使用自联接

select  t1.id,    
        i18n1.l_id l_id1,
        i18n1.t_id t_id1,
        i18n1.name name1,
        i18n2.l_id l_id2,
        i18n2.t_id t_id2,
        i18n2.name name2
from t t1
inner join t_i18n i18n1 on i18n1.t_id = t1.id and i18n1.l_id = 1
inner join t t2 on t1.id = t2.id
inner join t_i18n i18n2 on i18n2.t_id = t2.id and i18n2.l_id = 2
;
但是,它仅在假设t表中的每条记录在t_i18n表中始终有两条对应的记录(每种语言一条记录)的情况下工作。
如果某些记录只能有一种语言(lang-1或lang-2),则必须使用外部联接,如此查询中所示:

select *
from t
inner join t_i18n i18n
on i18n.t_id = t.id;
select  t1.id,    
        i18n1.l_id l_id1,
        i18n1.t_id t_id1,
        i18n1.name name1,
        i18n2.l_id l_id2,
        i18n2.t_id t_id2,
        i18n2.name name2
from t t1
left join t_i18n i18n1 on i18n1.t_id = t1.id and i18n1.l_id = 1
full outer join t t2 on t1.id = t2.id
left join t_i18n i18n2 on i18n2.t_id = t2.id and i18n2.l_id = 2

下面是第二种情况和两种查询的示例数据,看看它们是如何处理这些数据的。

通常
交叉表()
将是最快的。您需要在数据库中安装附加模块

SELECT * FROM crosstab(
   'SELECT t.id, l.name AS lang_name, i.name AS lang
    FROM   t
    JOIN   t_i18n i ON i.t_id = t.id
    JOIN   l  ON l.id = i.l_id'  -- could also just be "ORDER BY 1" here

   ,$$VALUES ('lang_1'::text), ('lang_2')$$)
AS l (id text, lang_1 text, lang_2 text);
如果您的案例实际上就这么简单(几乎从未如此),那么使用
case
语句进行查询就可以:

SELECT t.id
      , min(CASE WHEN i.l_id = 1 THEN i.name ELSE NULL END) AS lang_1
      , min(CASE WHEN i.l_id = 2 THEN i.name ELSE NULL END) AS lang_2
FROM               t
LEFT   JOIN t_i18n i ON i.t_id = t.id
LEFT   JOIN        l ON l.id = i.l_id
GROUP  BY 1
ORDER  BY 1;
此相关问题下两种解决方案的详细信息:

由于每个SQL查询和每个函数都必须具有定义良好的返回类型,因此不可能在单个查询中对动态数量的语言名称执行此操作。您可以编写一个函数来动态创建语句,并在第二次调用中执行该语句

还有多态类型的高级技术,我在这里写了一个全面的答案:


但是,上面简单的
交叉表()
查询可以很好地处理语言名称的超集。非存在语言的字段返回
NULL
。请查看。

看起来像是or问题的变体。试着搜索那些标签和
[postgresql]
标签。除了Craig的评论之外,我还补充了一点:查看模块中的
交叉表
功能。更复杂的是:表
l
中的列数不固定,别名(
lang\u 1
lang\u 2
)必须根据
l.id
值自动生成。有可能吗?@cetver:我添加了一些相关信息。稍微复杂一点:表
l
中的列数不是固定的,必须根据
l.id
值自动生成别名(
lang\u 1
lang\u 2
)。可能吗?