Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mysql sorting concated values

Tags:

php

mysql

I have 3 mysql tables (animal, category and animal_2_category). Every animal can have 0-n categories (for example fish, pet, insect, carnivore, "can fly", etc.).

Table "animal" (id, name)

1, dog
2, cat
3, bee
...

Table "categories" (id, name)

1, pet
2, insect
3, mammal
4, fish
5, can fly
...

Table "animal_2_category" (animal_id, category_id)

1, 1
1, 3
2, 1
2, 3
3, 2
3, 5
...

What I need now, is a list of all category combinations. The following query works:

SELECT CONCAT_WS("-", x.name, c.name)
FROM animal_2_category a2c1 
    JOIN animal_2_category a2c2 ON a2c1.animal_id = a2c2.animal_id
    JOIN category c ON c.id = a2c2.category_id´
    JOIN categories x
GROUP BY a2c2.category_id

This query wil return the following:

  • pet-mammal
  • mammal-pet
  • insect-can fly

The problem with this is, that I get dublicate entries "pet-mammal" and "mammal-pet". How can I modify the query, to only get one of them, for example:

  • pet-mammal
  • insect-can fly
like image 335
bernhardh Avatar asked Apr 29 '15 11:04

bernhardh


People also ask

Can you use || in MySQL?

The || , operator is a nonstandard MySQL extension. As of MySQL 8.0. 17, this operator is deprecated; expect support for it to be removed in a future version of MySQL. Applications should be adjusted to use the standard SQL OR operator.

How do I concatenate two column values in SQL?

Query: SELECT *, CONCAT(FIRSTNAME, LASTNAME) AS FIRSTNAME FROM demo_table; Output: Here, we can see that FIRSTNAME and LASTNAME is concatenated but there is no space between them, If you want to add space between the FIRSTNAME and LASTNAME then add space(' ') in CONCAT() function.

How do I concatenate 3 columns in SQL?

To concatenate more than 2 fields with SQL, you can use CONCAT() or CONCAT_WS() function.

Which operator concatenates two strings in a query result in MySQL?

The CONCAT() function adds two or more expressions together.


2 Answers

You can also rewrite your query as

SELECT  DISTINCT GREATEST(CONCAT_WS("-", x.name, c.name),CONCAT_WS("-", c.name, x.name)) col
FROM animal_2_category a2c1 
    JOIN animal_2_category a2c2 ON a2c1.animal_id = a2c2.animal_id
    JOIN categories c ON c.id = a2c2.`category_id`
    JOIN categories `x` ON a2c1.category_id = x.id
    WHERE x.name <> c.name

DEMO

like image 79
M Khalid Junaid Avatar answered Oct 10 '22 20:10

M Khalid Junaid


One way to avoid duplicate pairs is to ensure your pairs are always created in the same order. We can do that by assembling your pair in an if statement, which effectively sorts the two values for us. Then we just grab the distinct rows.

select distinct if(c1.name > c2.name, concat_ws('-', c1.name, c2.name), concat_ws('-', c2.name, c1.name)) pairing
  from animal_2_category a1
    inner join animal_2_category a2
      on a1.animal_id = a2.animal_id
        and a1.category_id <> a2.category_id
    inner join categories c1
      on a1.category_id = c1.id
    inner join categories c2
      on a2.category_id = c2.id;

Alternatively, just be more selective in the join criteria, so they only join in a particular order. This avoids the if, but we still need to grab the distinct values.

 select distinct concat_ws('-', c1.name, c2.name) pairing
  from animal_2_category a1
    inner join animal_2_category a2
      on a1.animal_id = a2.animal_id
        and a1.category_id < a2.category_id
    inner join categories c1
      on a1.category_id = c1.id
    inner join categories c2
      on a2.category_id = c2.id;

demo here

Either way, the results are the same.

like image 27
pala_ Avatar answered Oct 10 '22 20:10

pala_