Create a database model that shows a user's friends

0

Good evening I have a problem, I am creating a database which uses users who in turn have friends, I can show the relationship between users and their friends but I can not show the names of the friends (I can only show ID)

Users table:

CREATE TABLE usuario
(
 idUser serial NOT NULL,
 nombre TEXT,
 apellidoP TEXT,
 apellidoM TEXT,
 usuario TEXT,
 clave TEXT
);
ALTER TABLE usuario ADD CONSTRAINT PK_User PRIMARY KEY(idUser); 
INSERT INTO usuario (nombre,apellidoP,apellidoM,usuario, clave) VALUES ('Moises','Arias','Urbieta','dre0x', CRYPT('123456', GEN_SALT('md5')));
INSERT INTO usuario (nombre,apellidoP,apellidoM,usuario, clave) VALUES ('Marbella','Ramirez','de la Cruz','marbe', CRYPT('11112222', GEN_SALT('md5')));
INSERT INTO usuario (nombre,apellidoP,apellidoM,usuario, clave) VALUES ('Noel','Vazquez','Gomez','NoTrollOne', CRYPT('1111111', GEN_SALT('md5')));  

Table of friends:

CREATE TABLE friendlist (               
idUser INTEGER,             
idUser_FK INTEGER               
)               

ALTER TABLE friendlist ADD CONSTRAINT FK_User_Friends FOREIGN KEY (idUser) REFERENCES usuario(idUser);              
ALTER TABLE friendlist ADD CONSTRAINT FK_User_FK_Friends FOREIGN KEY (idUser_FK) REFERENCES usuario(idUser);                

INSERT INTO friendlist VALUES(1,2); 
INSERT INTO friendlist VALUES(1,3); 

Using this code, it shows me the following:

SELECT A.idUser, A.nombre, B.idUser_FK  FROM usuario A INNER JOIN friendlist B ON A.idUser = B.idUser;

iduser | nombre | iduser_fk
--------+--------+-----------
      1 | Moises |         2
      1 | Moises |         3
(2 filas)

I would like to show the names of the people who are friends of "Moises" but I can not do it. I hope you can help me

    
asked by Dreox 09.05.2017 в 04:39
source

2 answers

1

You should do another JOIN with the user table claiming the friendship relationship.

Example:

SELECT A1.idUser, A1.nombre, A2.idUser id_amigo, 
       A2.nombre nombre_amigo, B.idUser_FK  FROM usuario A1 
       INNER JOIN friendlist B ON A1.idUser = B.idUser
       INNER JOIN usuario A2 ON B.idUser_FK = A2.idUser;

Or, to make it clearer:

SELECT 

    A1.idUser, A1.nombre, 
    A2.idUser id_amigo, A2.nombre nombre_amigo, 

    B.idUser_FK  

    FROM friendlist B

    INNER JOIN usuario A1  ON A1.idUser = B.idUser
    INNER JOIN usuario A2 ON B.idUser_FK = A2.idUser;

The result will always be the same

Result

    iduser  nombre  id_amigo    nombre_amigo    iduser_fk
1   1       Moises  2           Marbella         2
2   1       Moises  3           Noel             3

Or, in a single row the friends of the user x , using aggregation functions (Postgresql), in MySQL would be easier with GROUP_CONCAT:

SELECT 

    A1.idUser, A1.nombre, 
    array_to_string(array_agg (A2.idUser), ', ') id_amigos, 
    array_to_string(array_agg (A2.nombre), ', ') nombre_amigos

    FROM friendlist B

    INNER JOIN usuario A1  ON A1.idUser = B.idUser
    INNER JOIN usuario A2 ON B.idUser_FK = A2.idUser

    GROUP BY A1.idUser;

Result

    iduser    nombre    id_amigos      nombre_amigos
1   1         Moises    2, 3           Marbella, Noel
    
answered by 09.05.2017 в 05:04
0

First your table friendlist is not consistent since you can insert the same friendship several times. To solve it, you must add a primary key. You should also try to define the foreign key during the creation of the table. Then I leave you said for the two tables:

In the user table you can remove the NOT NULL from idUser since a PRIMARY KEY implies that it can not be NULL .

CREATE TABLE usuario
(
     idUser serial PRIMARY KEY,
     nombre TEXT,
     apellidoP TEXT,
     apellidoM TEXT,
     usuario TEXT,
     clave TEXT
);

The friends table must reference both fields to the idUser field in the user table. And we form a PRIMARY KEY compound (when it is from a single field it can go in the same line that you define the field as I did in the previous table).

CREATE TABLE friendlist (               
    idUser INTEGER REFERENCES usuario(idUser),             
    idUser_FK INTEGER REFERENCES usuario(idUser),
    PRIMARY KEY(idUser, idUser_FK)
);    

If you execute the INSERT INTO that you had for friendlist you will see that they continue working, but if you try to insert the repeated data it will give an error. That allows each friendship relationship to be unique and that, for example, you have not repeated the friendship relationship between Moses and Marbella (with your previous code yes you could).

Regarding your query:

What you are doing is getting the friends of Moisés but in the friendlist table, and the only thing that appears in that table is its idUser_FK , which after all is a representative number but does not give us much information.

The solution is to perform another JOIN of the result with the table usuario . That way you can get the name of the friend knowing his iduser_FK obtained from the table friendlist .

Before seeing the consultations we summarize all this.

  • From your table usuario you get the rows of friendlist that have as idUser the id of Moses (come on, you're looking for the friends of Moses). At this point we know the idUser_FK of Moses' friends.

  • Those idUser_FK obtained from table friendlist we must return to look for them in the table usuario . You could say that you are looking in the table usuario the idUser that is equivalent to idUser_FK of the friends of Moses.

  • Step by step:

    1. We look for the id of the friends of Moisés in the friendship table (friendlist):

    SELECT lista.iduser_fk FROM 
    usuario usuario INNER JOIN friendlist lista ON    
    usuario.iduser=lista.iduser WHERE usuario.nombre='Moises';
    

    Getting the result:

    iduser_fk 
    -----------
         2
         3
    

    2.Now we should look for those id in the user table, modifying the query with a INNER JOIN with the table usuario :

    SELECT amigo.nombre FROM 
    usuario AS usuario INNER JOIN friendlist AS lista ON usuario.iduser=lista.iduser 
    INNER JOIN usuario AS amigo ON amigo.iduser=lista.iduser_fk
    WHERE usuario.nombre='Moises';
    

    The result is:

      nombre  
    ----------
     Marbella
     Noel
    

    You must also put the clause WHERE of the result that I have shown you because otherwise it will not filter by the name Moisés, in this even if you do not put WHERE the same result will come out because you only have friends for Moisés. but if you try to add another friendship relationship between two people other than Moses, he will also show it to you.

    To check what I'm saying, insert this new friendship between Marbella and Noel:

    INSERT INTO friendlist VALUES(2,3);
    

    If you make the query without the WHERE clause in the end, Noel shows you twice, because Noel is a friend of Marbella and Moisés:

    SELECT amigo.nombre FROM 
    usuario AS usuario INNER JOIN friendlist AS lista ON     
    usuario.iduser=lista.iduser 
    INNER JOIN usuario AS amigo ON amigo.iduser=lista.iduser_fk;
    
      nombre  
    ----------
     Marbella
     Noel
     Noel
    

    I hope it serves you, if you have any questions do not hesitate to send a message:)

        
    answered by 10.06.2017 в 15:42