mysql select distinct rows into a comma delimited list column - mysql

I currently have some sql that brings back tags. they should have distinct ids, but they don't.... so my current data is like:
Microsoft | GGG | 1 | 167
Microsoft | GGG | 1 | 2
Microsoft | GGG | 1 | 1
What i would like to do is have only one row come back with the final column concatenated into a delimited list like:
Microsoft | GGG | 1 | 167, 2, 1
I am using mySQL 5 for this.

Use GROUP_CONCAT() for this, with a GROUP BY covering the other three columns:
SELECT
name, -- Microsoft
other, -- GGG
other2, -- 1
GROUP_CONCAT(id) AS ids
FROM tbl
GROUP BY name, other, other2

Related

given two tables and a third table relating the two, select only the rows from table A that match a list of table B rows, but don't match another list

My test schema, data, and query: https://www.db-fiddle.com/f/apQXP7MGfDKPHVw6ucmuNv/1
My query should select only the cars that match ALL of the IN () part features, and NONE of the NOT IN (), and it should only select each matching car once.
In my sample data, when I run the query, I expect to see a single row with two columns, containing the id and name of the only car that matches the list of features in the IN () part of the where clause without matching the list of features in the NOT IN () part of the where clause:
1 | camry
Instead, I get a row containing the name of a car every time that car matches one of the values in the IN () part of the where clause:
1 | camry | 2 | 1 | 2 | 2 | backup camera
1 | camry | 3 | 1 | 3 | 3 | sun roof
2 | forester | 4 | 2 | 2 | 2 | backup camera
2 | forester | 5 | 2 | 3 | 3 | sun roof
If you want one row per car you need aggregation. I think what you want is:
SELECT c.id, c.name
FROM `car` c JOIN
`bridge_car_features` cf
ON car.id = bridge.car_id JOIn
`features` f
ON cf.features_id = f.id
GROUP BY c.id
HAVING SUM(f.name IN ('backup camera', 'sun roof')) > 0 AND -- has at least one of these
SUM(f.name IN ('four wheel drive')) = 0; -- has none of these
Here is a fiddle.
Note: For the fiddle to work, I made the id be a primary key on cars.

MySQL ORDER By one Specific value in column (having comma separated values)

I want to sort the user record according to city (chosen from the drop-down list). like if I pass city_id 22 in my query then i want all the row first which are having city_ids 22 then the rest of the rows.
I know WHERE find_in_set('22',city_ids) will give me the correct result but it will not return the all rows so I want to achieve it using some ORDER BY .
I have tried ORDER BY FIND_IN_SET('22',city_ids) but its not working. How do I fix this, any best way?
User Table:
Id Name city_ids
1 AAAAA 10,22,30
2 BBBBB 11,28
3 CCCCC 15,22,44
4 DDDDD 19,99,
5 EEEEE 55,27,22
Want Sorted Output like below:
Id Name city_ids
1 AAAAA 10,22,30
3 CCCCC 15,22,44
5 EEEEE 55,27,22
2 BBBBB 11,28
4 DDDDD 19,99,
You can do:
ORDER BY (FIND_IN_SET('22', city_ids) > 0) DESC
This puts matches first.
Then you should fix your data model. It is broken, broken, broken. Storing lists of ids in a string is wrong for many reasons:
The data types are (presumably) wrong. The ids are numbers and should not be stored as strings.
Storing multiple values in a column is not the SQL way to store things.
Ids should have properly declared foreign key relationships, which you cannot declare.
SQL does not have very good functions for processing strings.
The resulting queries cannot take advantage of indexes or partitioning, impeding performance.
SQL has this really great data structure for storing lists of things. It is called a table, not a string column.
The expression:
FIND_IN_SET('22', city_ids) > 0
will return 1 for all rows where '22' exists in column city_ids and 0 for the others.
So, after that you need add one more level for sorting by id ascending:
ORDER BY
FIND_IN_SET('22', city_ids) > 0 DESC,
id
See the demo.
Results:
| Id | Name | city_ids |
| --- | ----- | -------- |
| 1 | AAAAA | 10,22,30 |
| 3 | CCCCC | 15,22,44 |
| 5 | EEEEE | 55,27,22 |
| 2 | BBBBB | 11,28 |
| 4 | DDDDD | 19,99 |

Skipping row for each unique column value

I have a table from which I would like to extract all of the column values for all rows. However, the query needs to be able to skip the first entry for each unique value of id_customer. It can be assumed that there will always be at least two rows containing the same id_customer.
I've compiled some sample data which can be found here: http://sqlfiddle.com/#!9/c85b73/1
The results I would like to achieve are something like this:
id_customer | id_cart | date
----------- | ------- | -------------------
1 | 102 | 2017-11-12 12:41:16
2 | 104 | 2015-09-04 17:23:54
2 | 105 | 2014-06-05 02:43:42
3 | 107 | 2011-12-01 11:32:21
Please let me know if any more information/better explanation is required, I expect it's quiet a niche solution.
One method is:
select c.*
from carts c
where c.date > (select min(c2.date) from carts c2 where c2.id_customer = c.id_customer);
If your data is large, you want an index on carts(id_customer, date).

get duplicated fields and these fields may have spaces in mysql database

I have this mysql table
id | phone | name
1 | 123456| aaaa
2 | 454535| bbbb
3 | 123456| cccc
4 | 123456 | ddd
based on above data these records:
1 | 123456| aaaa
3 | 123456| cccc
4 | 123456 | ddd
are duplicated but the first one is trimmed and second has space at the beginning and the third has space at the end.
I have written this query:
SELECT phone, count(trim(phone)) FROM users GROUP BY trim(phone) HAVING count(trim(phone)) > 1
but did not return any records.
May be your problem with Check for line break or carriage return. No problem with white space.
SELECT * FROM users WHERE phone REGEXP "\r\n";
Here is a slightly cleaned up version fo your query.
SELECT TRIM(phone), count(id) AS Counter
FROM users
GROUP BY TRIM(phone)
HAVING Counter > 1
This query returns the following result:
phone | Counter
123456 | 3

MySQL Table Structure - Storing a limited set of numbers

I need to store a set of numbers in a MySQL database. I need some help to determine the best table structure to use.
There are 20 numbers that will be stored in each row, along with an ID. The numbers can range from 1 - 80 and there are no repeats in this series of numbers.
Initially I created a table structure with 21 columns, an ID and 20 columns that store each individual number.
Id | Num1 | Num2 | Num3 | Num4 | Num5 | etc.. |
----------------------------------------------------------
0001 | 1 | 4 | 15 | 22 | 39 | 43 |
0002 | 3 | 5 | 22 | 43 | 55 | 58 |
0003 | 1 | 3 | 5 | 6 | 15 | 26 |
I've also thought of a table with 81 columns, an ID and 80 boolean columns that would represent each individual number.
Id | 1 | 2 | 3 | 4 | 5 | etc.. |
----------------------------------------------------------
0001 | True | False | False | True | True | False |
0002 | False | False | True | False | True | False |
0003 | True | False | True | False | True | True |
Can anyone give some advice to the pros and cons of each table structure, and which would be easier to use when searching this table.
For example, we would need to search for every row that contains 1,2,5,66, and 79.
Or every row that contains 16,33, and 4.
Any guidence would be appreciated.
What you're looking for is called database normalization; a way to organize data that prevents duplication and anomalies (like changing one record inadvertently changing another record).
Higher-normal forms depend on the meaning of your data, which you have not told us, but to start you should avoid ordered or indeterminate columns (like Num1, Num2, ...) and split your columns into rows:
ID Num
0001 1
0001 4
0001 15
...
0002 3
0002 5
...
In general, any time you find yourself adding a bunch of columns that depend on their position you are making a mistake. SQL has many functions for aggregating, combining, sorting, and reporting on rows. Use the features of SQL to produce the results you want; don't try to make your database schema look like the final printed report.
In answer to your comment, a query that returns only IDs that have Nums 1, 4, and 15, and no other ID:
select ID from YourTable
where Num in (1, 4, 15)
group by ID
having Count(ID) = 3
If Nums can be duplicated you will want something like having count(distinct ID). If you can have different counts of Nums to match you will have to create a temporary table of Nums to match and use having count(ID) = (select Count(Num) from TemporaryTable).
Note that SQL Server already has a master..spt_values table of integers to use in such situations; I do not know if MySql has such a thing, but they are easy to generate if you need one.