How to select multiple results in one row

Asked

Viewed 4,226 times

1

The problem: One of our sites has a messaging system between users, for this we have two tables: one that stores the messages between users and the other with users, follow the structures below,and with this data we need to display in the messages the name of all users to which the message was sent.

At first I thought I’d make a select for the messages and with the user id of this message generate another string of select’s within a while, but it seemed wrong to me and searching through the internet I found no alternative to this situation. Would anyone have a solution to this problem? It would have to do a single select to get both users' names and the message?

Follow the structures:

TABLE messages:

  • id INT PRIMARY KEY,
  • id_users: 'Relates to user id, Ex: 1,27,1247,88',
  • title 'message title',
  • text 'from the message',

TABLE users:

  • id INT PRIMARY KEY,
  • name 'user name',
  • etc..

3 answers

2


Even if you create an SQL for this, it will cost you a lot of processing, because you will have to break this string id_users in a list, and do a JOIN on top of it.

What I suggest is that you refocus your structure, using the way the vast majority of systems work in this situation. This way:

TABLE messages:

id INT PRIMARY KEY,
title 'titulo da mensagem',
text 'texto da mensagem',

TABLE users:

id INT PRIMARY KEY,
name 'nome do usuario',

TABLE users_messages:

id INT PRIMARY KEY
id_user (FK)
id_mensagem (FK)

It is a super basic structure Many-to-Many, ie, a message can belong to 1 or more users, and a user can have 1 or more messages. With that, your query stays this way:

SELECT u.id, u.name, m.id
    FROM users u
    JOIN users_mensagens um ON um.id_users = u.`id`
    JOIN mensagens m ON m.id = um.id_mensagens;
  • the problem is that this query returns me only the name of one of the users and a message can have up to 20 users linked to it... =/

  • Opa, Perai, now that I realize, the value of the id_users field is a string with the ids separated by comma?

  • That’s right @rafaels88!

  • I’ll edit my answer for you.

2

A friend (@rodrigoborth) helped me talking about 'FIND_IN_SET', which made me arrive in the following query:

SELECT mensagens.id, users.name, mensagens.title, mensagens.date
    FROM mensagens INNER JOIN users
        WHERE FIND_IN_SET( users.id , mensagens.id_users ) ORDER BY mensagens.id

Simplifying my problem and thus temporarily answering the question! =)

  • 1

    That helped a bit already :D

1

Its database seems denormalized, I advise if possible, the creation of a table to relate the user to message. But it follows an option using a sub-query to bring users related to the message, reducing the number of query result lines.

SELECT
m.title,
m.text,
m.id_users,
(
  SELECT 
  GROUP_CONCAT(u.name SEPARATOR ';')
  FROM users u 
  WHERE FIND_IN_SET(u.id,m.id_users)
) as nomes
FROM mensagens m

In this case the query returns the users related to the message in the format usuario1;usuário2

Example: Sqlfiddle

  • Doubt: This will not generate a slow query, even if I apply the idea of @rafaels88 to your answer?

  • @Mateusdemboski my answer is based on your current structure, as I said, the correct is for you to create a table for the entities' relationship.

  • so that’s my idea, creates the table for the relationship and use part of your query to generate the result, because that’s exactly what your query does what I need, but it hit me the question if it would not generate a slow query

  • @Mateusdemboski I understand, more if it will generate a slow query depends on N factors.

  • 1

    @Mateusdemboski, the ideal is for you to do this kind of processing, to join with ;, in your application code, and not in SQL. SQL does not have to be responsible for data logic. If you want to port your system to another server that does not have the FIND_IN_SET function in the future, your system will not work. But if you do this in code, and not in SQL, you will never go through it.

  • @rafaels88, as I said, my answer was based on the current structure, is the way I found to return the query as he wishes, also agree that this is not the best way to do, more depends, whether the current system is already in production and can notif changing the database to create a new table, this would be an output.

  • @abfurlan I fully understood what you meant, and I fully agree. My comment was intended for Mateusdemboski himself. If he’s got a chance to change that, he better make it before it turns into a big noodle. =)

  • 1

    @rafaels88 understood, I think we agreed that is not the best way :P

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.