Many-to-many relationships postgrest, consultation to take out in a single row

2

I have a table A :

-----------------------------
| id  |   nombre   |   cel  |
-----------------------------
|1    | Juan       | 1653727|
|2    | Pedro      | 6353526|
|3    | Hernan     | 4465672|
-----------------------------

Another table B :

--------------------
| id  | material   |
--------------------
|1    | lapiz      |
|2    | cuaderno   |
|3    | mochila    |
--------------------

And an intemedia table AB :

-----------------------------
| id_A  | id_B   | cantidad |
-----------------------------
|1      |   1    |    3     |
|1      |   2    |    2     |
|2      |   1    |    2     |
|2      |   2    |    2     |
|3      |   1    |    4     |
|3      |   2    |    1     |
|3      |   3    |    1     |
-----------------------------

And I have a query like this:

SELECT 
   A.nombre nombre, 
   B.material material,
   AB.cantidad cantidad  
FROM AB
INNER JOIN A ON AB.id_A =  A.id
INNER JOIN B ON AB.id_B =  B.id

And the result is the following:

----------------------------------
| nombre  | material  | cantidad |
----------------------------------
| Juan    |  lapiz    |    3     |
| Juan    | cuaderno  |    2     |
| Pedro   |  lapiz    |    2     |
| Pedro   | cuaderno  |    2     |
| Hernan  |  lapiz    |    4     |
| Hernan  | cuaderno  |    1     |
| Hernan  | mochila   |    1     |
----------------------------------
  

The problem is that I have repeated names and I do not want them that way.

The format I want is the following:

------------------------------------------------
| nombre   | lapiz   |  cuaderno  |   mochila  |
------------------------------------------------
| Juan     |   3     |     2      |     0      |
| Pedro    |   2     |     2      |     0      |
| Hernan   |   4     |     1      |     1      |
------------------------------------------------

I do not know if it is possible to do this with a query, function or stored procedure in postgres .

I appreciate any help you can give me.

    
asked by Shassain 03.06.2018 в 20:58
source

2 answers

2

First of all, I must say that in my opinion this type of query should be resolved in the hearing and not in the engine, but if you still need to do it, the most basic and standard form (except for the use of coalesce ) would be to make a LEFT JOIN for each material. Something like this:

SELECT A.nombre,
       coalesce(Lapiz.Cantidad,0)     Lapiz,
       coalesce(Cuaderno.Cantidad,0)  Cuaderno,
       coalesce(Mochila.Cantidad,0)   Mochila
       FROM A
       LEFT JOIN (SELECT AB.id_A, AB.Cantidad
                         FROM AB
                         WHERE id_B = 1 -- Id de Lapiz
            ) Lapiz
            ON Lapiz.id_A = A.id
       LEFT JOIN (SELECT AB.id_A, AB.Cantidad
                         FROM AB
                      WHERE id_B = 2 -- Id de cuaderno
            ) Cuaderno
            ON Cuaderno.id_A = A.id
       LEFT JOIN (SELECT AB.id_A, AB.Cantidad
                         FROM AB
                         WHERE id_B = 3 -- Id de mochila
            ) Mochila
            ON Mochila.id_A = A.id
;

The exit:

| nombre | lapiz | cuaderno | mochila |
|--------|-------|----------|---------|
|   Juan |     3 |        2 |       0 |
|  Pedro |     2 |        2 |       0 |
| Hernan |     4 |        1 |       1 |

SQLFiddle

If you wanted to "accommodate" 20 materials in a single query you should build a similar query, with 20 LEFT JOIN for each of the selected materials.

There is also the possibility of using an extended function crosstab but I have no way to try it, so I'll just give you a reference to this question

    
answered by 04.06.2018 / 18:24
source
0

Add the condition of DISTINCT to your SQL statement, which will be responsible for filtering the data that is repeated; which in this case is the name of the person

SELECT DISTINCT 
   A.nombre nombre, 
   B.material material,
   AB.cantidad cantidad  
FROM AB
INNER JOIN A ON AB.id_A =  A.id
INNER JOIN B ON AB.id_B =  B.id
  

UPDATE

     

You must add an offset at the end of your query to be clear about the   limit of results to return that in your case could be left of this   mode

SELECT DISTINCT 
   A.nombre nombre, 
   B.material material,
   AB.cantidad cantidad  
FROM AB
INNER JOIN A ON AB.id_A =  A.id
INNER JOIN B ON AB.id_B =  B.id LIMIT 1,3;

What it means to return me 3 records starting at record number 1; the syntax there is shortened but it may look like this:

LIMIT 3 OFFSET 1;

is equal to:

LIMIT 1, 3;
    
answered by 03.06.2018 в 21:11