Postgres查询矩阵表

时间:2016-09-07 04:50:51

标签: php mysql postgresql matrix

我想在MySQL或postgres中进行查询,这些查询将从4个表中生成。

请参阅下表。

我想在下面定义的矩阵表中使用postgres或sql查询。

如何使用SQL实现此目的?

提前多多谢谢你。

表:目标

+----+-------------+
| id | name        |
+----+-------------+
|  1 | 9999999991  |
|  2 | 9999999992  |
|  3 | 9999999993  |
|  4 | 9999999994  |
|  5 | 9999999995  |
|  6 | 9999999996  |
|  7 | 9999999997  |
|  8 | 9999999998  |
+----+-------------+

表:Target_groups

+----+-------------+
| id | name        |
+----+-------------+
|  1 | Group 1     |
|  2 | Group 2     |
|  3 | Group 3     |
|  4 | Group 4     |
+----+-------------+

表格:Target_groups_map

+----+-----------+--------------+
| id |targets    | target_groups|
+----+-----------+--------------+
|  1 | 9999999991|    1         |
|  2 | 9999999992|    1         |
|  3 | 9999999993|    2         |
|  4 | 9999999994|    2         |
|  5 | 9999999995|    3         |
|  6 | 9999999996|    3         |
|  6 | 9999999997|    4         |
|  6 | 9999999998|    4         |
+----+-----------+--------------+

表:Call_details

+----+-----------+--------------+
| id | caller    | called       |
+----+-----------+--------------+
|  1 | 9999999995| 9999999996   |
|  2 | 9999999992| 9999999998   |
|  3 | 9999999993| 9999999998   |
|  4 | 9999999994| 9999999991   |
|  5 | 9999999995| 9999999998   |
|  6 | 9999999996| 9999999992   |
|  6 | 9999999991| 9999999993   |
|  6 | 9999999992| 9999999998   |
+----+-----------+--------------+
我想要的

矩阵表

+--------+--------+--------+--------+--------+
|        | Group 1| Group 2| Group 3| Group 4|
+--------+--------+--------+--------+--------+
| Group 1|     -  |     1  |     -  |     2  |
| Group 2|     1  |     -  |     -  |     1  |
| Group 3|     1  |     -  |     1  |     1  | 
| Group 4|     -  |     -  |     -  |     -  |
+--------+--------+--------+--------+--------+

4 个答案:

答案 0 :(得分:3)

在Postgres中,您需要扩展程序tablefunc来生成 pivot 表:

<p>Regular text here</p>
<p class="rtl">Persian text here</p>
<p class="justify">Justified Regular text here</p>
<p class="rtl justify">Justified Persian text here</p>

create extension if not exists tablefunc; 的查询:

crosstab()

使用汇总函数string_agg()代替select * from crosstab($$ select t1.name caller_name, t2.name called_name, count from target_groups t1 cross join target_groups t2 left join ( select c1, c2, count(*)::int from ( select g1.target_groups c1, g2.target_groups c2 from call_details c join target_groups_map g1 on c.caller = g1.targets join target_groups_map g2 on c.called = g2.targets ) c group by 1, 2 order by 1, 2 ) c on t1.id = c1 and t2.id = c2 $$) as ct (" " text, "Group 1" int, "Group 2" int, "Group 3" int, "Group 4" int) | Group 1 | Group 2 | Group 3 | Group 4 ---------+---------+---------+---------+--------- Group 1 | | 1 | | 2 Group 2 | 1 | | | 1 Group 3 | 1 | | 1 | 1 Group 4 | | | | (4 rows) 的相同查询:

crosstab()

答案 1 :(得分:0)

...的MySQL

这是一个挑战。我将介绍所需的两个步骤:

首先,让我们构建(和调试)一个查询,列出所有调用者调用的对,其中一些是重复的。 (我们稍后会计算它们。)

SELECT ger.name AS er_name,
       ged.name AS ed_name
FROM Call_details AS cd
JOIN Target_groups_map AS mer  ON mer.targets = cd.caller
JOIN Target_groups_map AS med  ON med.targets = cd.called
JOIN Target_groups AS ger ON ger.id = mer.target_groups
JOIN Target_groups AS ged ON ged.id = med.target_groups;

其次,让我们进行转移,计算重复次数,默认为&#39; - &#39;等等:

SELECT
er_name                               AS '',
IFNULL(SUM(ed_name = 'Group 1'), '-') AS 'Group 1',
IFNULL(SUM(ed_name = 'Group 2'), '-') AS 'Group 2',
IFNULL(SUM(ed_name = 'Group 3'), '-') AS 'Group 3',
IFNULL(SUM(ed_name = 'Group 4'), '-') AS 'Group 4'
FROM ( ... ) AS y
GROUP BY er_name;

对于&#39; ...&#39;从第一步开始整个查询(不要包含;&#39;)。

SUM可能看起来很奇怪,但这里的工作原理是:它内部的布尔表达式变为0(假)或1(真),然后SUM有效计数。 / p>

如果组的数量不完全是4,那么您应该放弃尝试在SQL中执行此操作。当然,可以通过一个非常复杂的存储过程来构建第二个查询,但这会让我的大脑受到伤害。

每当我进行透视时,我都会用客户端语言编写代码,例如PHP。

答案 2 :(得分:0)

这个sql语句:

SELECT 
  tg1.name as caller, 
  tg2.name as called, 
  SUM(cd.caller IS NOT NULL AND cd.called IS NOT NULL) as cnt 
FROM 
  Target_groups tg1 JOIN Target_groups tg2   
  LEFT JOIN 
    Target_groups_map tgm1 ON tg1.id=tgm1.target_groups
  LEFT JOIN 
    Target_groups_map tgm2 ON tg2.id=tgm2.target_groups
  LEFT JOIN
    Call_details cd ON tgm1.targets=cd.caller AND tgm2.targets=cd.called
GROUP BY
  tg1.id,tg2.id;

给出:

+---------+---------+------+
| caller  | called  | cnt  |
+---------+---------+------+
| Group 1 | Group 1 |    0 |
| Group 1 | Group 2 |    1 |
| Group 1 | Group 3 |    0 |
| Group 1 | Group 4 |    2 |
| Group 2 | Group 1 |    1 |
| Group 2 | Group 2 |    0 |
| Group 2 | Group 3 |    0 |
| Group 2 | Group 4 |    1 |
| Group 3 | Group 1 |    1 |
| Group 3 | Group 2 |    0 |
| Group 3 | Group 3 |    1 |
| Group 3 | Group 4 |    1 |
| Group 4 | Group 1 |    0 |
| Group 4 | Group 2 |    0 |
| Group 4 | Group 3 |    0 |
| Group 4 | Group 4 |    0 |
+---------+---------+------+

但是如果你想要格式化你打印出来的方式你需要一个准备好的sql语句,然后做Rick James先生所说的,如果你需要它动态(不要事先知道组名)这里是一个起点:

SET @sql = NULL; SELECT GROUP_CONCAT(DISTINCT(CONCAT('"" as ',quote(name)))) INTO @sql FROM Target_groups; SET @sql = CONCAT("SELECT Target_groups.name, ", @sql, " FROM Target_groups"); PREPARE stmt FROM @sql; EXECUTE stmt;

Statement prepared

+---------+---------+---------+---------+---------+
| name    | Group 1 | Group 2 | Group 3 | Group 4 |
+---------+---------+---------+---------+---------+
| Group 1 |         |         |         |         |
| Group 2 |         |         |         |         |
| Group 3 |         |         |         |         |
| Group 4 |         |         |         |         |
+---------+---------+---------+---------+---------+

ps - 这是为了帮助任何人试图解决这个+测试:

create table Targets (id int, name bigint) engine=innodb;
insert into Targets values (1,9999999991),(2,9999999992),(3,9999999993),(4,9999999994),(5,9999999995),(6,9999999996),(7,9999999997),(8,9999999998);

create table Target_groups (id int, name varchar(16)) engine=innodb;
insert into Target_groups values (1,'Group 1'),(2,'Group 2'),(3,'Group 3'),(4,'Group 4');

create table Target_groups_map (id int,targets bigint,target_groups int) engine=innodb;
insert into Target_groups_map values (1,9999999991,1),(2,9999999992,1),(3,9999999993,2),(4,9999999994,2),(5,9999999995,3),(6,9999999996,3),(6,9999999997,4),(6,9999999998,4);

create table Call_details (id int,caller bigint,called bigint) engine=innodb;
insert into Call_details values (1,9999999995,9999999996),(2,9999999992,9999999998),(3,9999999993,9999999998),(4,9999999994,9999999991),(5,9999999995,9999999998),(6,9999999996,9999999992),(6,9999999991,9999999993),(6,9999999992,9999999998);

答案 3 :(得分:-1)

我提出了一个问题:

Select A.name as caller,A.ToGroupName as called,Count(phone_number) as count
From (
                Select G.id,T.phone_number,G.Name,FC.Called,TG.name as ToGroupName
                From targets T
                LEFT Join target_groups_map GM on GM.targets = T.phone_number
                Left Join target_groups G on G.id = GM.target_groups
                INNER Join call_details FC on FC.Caller = T.phone_number
                INNER Join target_groups_map TGM on TGM.targets = FC.called
                Inner Join target_groups TG on TG.id = TGM.target_groups
) A
Group By A.name,A.ToGroupName
Order By A.name,A.ToGroupName

提供输出:

+---------+---------+------+
| caller  | called  | cnt  |
+---------+---------+------+
| Group 1 | Group 2 |    1 |
| Group 1 | Group 4 |    3 |
| Group 1 | Group 5 |    2 |
| Group 2 | Group 1 |    2 |
| Group 2 | Group 4 |    1 |
| Group 2 | Group 5 |    3 |
| Group 3 | Group 1 |    1 |
| Group 3 | Group 3 |    1 |
| Group 3 | Group 4 |    1 |
| Group 3 | Group 5 |    1 |
| Group 4 | Group 2 |    1 |
| Group 5 | Group 2 |    2 |
+---------+---------+------+

将其转换为矩阵格式