group_concat many times? - mysql

I'm trying to make a MySQL query that uses different group_concat with data from the same LEFT JOIN. An example tables could be:
Cars table
carid | license_plate
Tires table (means used tires)
carid | model | width
From these tables i want to obtain a list of tire models classified by their width, with the idea that there are only two different possible widths and I'm loading it from a car card page.
SELECT name,
if(width=205,group_concat(model ORDER BY model ASC),'') as width_205,
if(width=225,group_concat(model ORDER BY model ASC),'') as width_225,
FROM cars
LEFT JOIN tires ON cars.carid=tires.carid
WHERE carid='10'
I hope that my explanation is clear. This sentence doesn't work properly, and I don't know if it's because of a bad syntax or that I simply can't use group_concat this way.
Well, thanks for reading and I'll be waiting for your answers. Thanks in advance!

Try
SELECT name,
GROUP_CONCAT(CASE width WHEN 205 THEN model ELSE NULL END CASE AS model ORDER BY model) as width_205,
GROUP_CONCAT(CASE width WHEN 225 THEN model ELSE NULL END CASE AS model ORDER BY model) as width_225,
FROM cars
LEFT JOIN tires ON cars.carid=tires.carid
WHERE carid='10'
GROUP BY name
to get what you want. I don't have MySQL handy to test. You may have to fool with (or even give up) the internal ORDER BY.
Alternatively, you can get back two rows (and not have to change your SQL if a third size is ever added) with:
SELECT name, width, GROUP_CONCAT(model ORDER BY model) AS Models
FROM cars
LEFT JOIN tires ON cars.carid=tires.carid
WHERE carid='10'
GROUP BY name, width

Both solutions are great! Maybe the second is more elegant and finally it's the one I'll use, but I'll take note also from the first because it's more concrete and can be better for some situations.
For the first method to work I had to delete "CASE AS model" after the "END" to prevent MySQL errors:
SELECT name,
GROUP_CONCAT(CASE width WHEN 205 THEN model ELSE NULL END ORDER BY model) as width_205,
GROUP_CONCAT(CASE width WHEN 225 THEN model ELSE NULL END ORDER BY model) as width_225,
FROM cars
LEFT JOIN tires ON cars.carid=tires.carid
WHERE carid='10'
GROUP BY name
I also have added a DISTINCT before the CASE inside group_concat, to avoid repetitions.
For the second method, I only have added an "ORDER BY width ASC" at the end of the sentence. For anyone else that may need this method, don't forget that mysql_fetch_(whatever) already takes the first result that contains the first case of the group_concat.
Thanks a lot! CU

Related

MYSQL Group By Returning Duplicate Values

I am seeing a weird problem with MYSQL GROUP BY.
I have a query...
SELECT schools.schoolregion,
Count(schools.schoolregion) AS regioncount,
(
SELECT Count(jobs_jobsubject)
FROM 'jobs'
WHERE 'jobs_createdDate' BETWEEN '$startofyear'
AND '$endofyear') AS regionjobstotal
FROM 'jobs'
LEFT JOIN 'schools'
ON 'jobs_schoolID'='SID'
WHERE 'jobs_createdDate' BETWEEN '$startofyear'
AND '$endofyear'
GROUP BY 'schoolRegion'
...in which I am attempting to total the number of job postings listed per region and group by region. I have two tables, one with a list of schools and another with job information that has a column value that joins back to the school. I need the region total, and the overall total of jobs within a time period (hence the sub query).
When I run this query, I get everything that I expect - except that I am getting a duplicate region listing in the returned results of the GROUP BY function.
For example, here is the table that I am getting but not sure why the duplicate for the Middle East.
schoolRegion regioncount regionjobstotal
Africa 1 38
Asia 6 38
Middle East 20 38
Middle East 11 38
I thought maybe there was an extra character or something, but I could not find/see anything different about the values within the tables - which for that column is being stored as type "text". Is there anything I can check for? Is it something to do with the query?
Any help would be fantastic and much appreciated!!
My guess is that the data is not ordered by schoolRegion. I would add an ORDER BY schoolRegion ASC to your query to ensure that they are organized thusly. :)
OMG, do I feel like a noob!!
When I adjusted the query to list the schools, there was only one school that was not included in the GROUP BY. Initially when I looked at this hours ago, inline editing in PHPMYADMIN didn't show that there was a character return AFTER the text - so I wrote off that it was the text of the value being stored. But when I checked the box to edit the row individually and not inline and went to that column value - low and behold - a carriage return!!! Sometimes it's the little things like that which kill and humble me.
First, i do not think you can supply a child select statement as a column in your parent select statement "(SELECT COUNT(jobs_jobSubject)...".
Also since the where clause for your child and parent select are thesame, why not use a single select statement and get the count of both.
SELECT schools.schoolRegion,
COUNT(schools.schoolRegion) AS regioncount,
COUNT(jobs_jobSubject) AS regionjobstotal
FROM 'jobs' jb
INNER JOIN 'schools' sc ON jb.jobs_schoolID=sc.SID
WHERE 'jobs_createdDate'
BETWEEN '$startofyear' AND '$endofyear'
GROUP BY 'schoolRegion'

Looking for an efficient way to translate values in a huge MariaDB table by information in another, very small table

Problem:
In a table a with 10 mio rows I have a column a.profession_id of coded professions of customers (0, 1, 2, ...).
In another very small table b I have some (not all) "translations" for these professions (0 = unemployed, 1 = worker, ...).
Goal:
I want to enhance my huge table with the existing Information in an efficient (fast) way.
Not working:
INNER JOIN since I don't have all translations
Classic LEFT JOIN since an index on a.profession_id will not be used and an index on b.profession_id won't Speed things up enogh
SELECT * FROM a LEFT JOIN b ON a.profession_id = b.profession_id
Solution:
Non so far, do you have a clever input?
If you absolutely have to do the translation, and can't avoid doing it...
The second best option (purely in terms of database performance and no other considerations) is to ignore the small table and use a static expression in the SELECT list:
SELECT r.profession_id
, CASE r.profession_id
WHEN 0 THEN 'unemployed'
WHEN 1 THEN 'worker'
WHEN 2 THEN '...'
ELSE ''
END AS profession_name
FROM table_with_10_mio_rows r
There's drawbacks to that approach, if that profession lookup list isn't static. (If that had been had a static list, and profession isn't an entity in our data model, we might have actually considered implementing profession as a enum datatype.)
As a separate step, to help us quickly fill in that CASE expression, we could make use of the lookup table:
SELECT CONCAT(' WHEN ',t.id,' THEN ''',REPLACE(t.name,'''',''''''),'''') AS expr
FROM small_profession_lookup_table t
ORDER BY id
If some professions are much higher frequency, move those to the top of the list.

GROUP CONCATing multiple rows

I'm using MySQL 5.1.66 and I came up with a select query to select all the men's shirts and their sizes and prices. I used GROUP CONCAT to merge the size column and price column from their parent tables into the same column. Here's the statement I made
SELECT shirts.shirt_name, shirts.men AS main_photo,
GROUP_CONCAT(shirt_sizes.size_name,shirt_prices.price) AS sizes
FROM shirts
JOIN shirts_link ON shirts_link.shirt_id=shirts.id
JOIN shirt_sizes ON shirt_sizes.id=shirts_link.size_id
JOIN shirt_prices ON shirt_prices.id=shirts_link.price_id
WHERE shirts.men!='' AND shirts_link.adult='y'
GROUP BY shirts.id
By doing this, are the size columns and price columns still two separate entities within that one column in the select statement? Another thing I noticed is the order of the sizes is all mixed up. For example, this is a row from one of the columns
medium29.22,large29.22,1x-large29.22,2x-large30.44,small29.22,3x-large31.70
why isn't it going from small-3x like it's organized on the table? I imagine in the event of what I'm trying to do in terms of injecting it into we website through PHP if it were to auto load it would go in that unorganized manner as well. How can I fix this?
My ultimate goal here is to be able to create a selection that can auto populate each row into the javascript apps I created. I need the load the shirt name, main picture, then each size and price into the divs I have coded for them. Let me know if you need to see the actual tables being used. Thanks in advance :)
First of all purpose of group_concat function is to keep all values of a particular column in a grouped operation. For example,
Table1
ID field1 field2
1 ram science
2 ramesh maths
1 ram maths
If your requirement is to get subjects of a particular person then GROUP_CONCAT will produce then result as follows,
ID field1 field3
1 ram science,maths
2 ramesh maths
Hope this gives some insight
Try this:
SELECT s.shirt_name, s.men AS main_photo,
GROUP_CONCAT(CONCAT(ss.size_name, '.', sp.price)) AS sizes
FROM shirts s
INNER JOIN shirts_link sl ON sl.shirt_id = s.id
INNER JOIN shirt_sizes ss ON ss.id = sl.size_id
INNER JOIN shirt_prices sp ON sp.id = sl.price_id
WHERE s.men!='' AND sl.adult='y'
GROUP BY s.id

MYSQL Tuple in IN CLause with wildcard matching

I have the following problem. suppose I have a table containing an inventory of cars:
VIN, MAKE, MODEL, PRICE
AND I have another table containing various car classes( eg, compact, mid-sized, suv, etc)
MAKE, MODEL, CLASS
JEEP, NULL , SUV
FORD, EXPLORER, SUV
TOYOTA, YARIS, COMPACT
NULL, CUBE, COMPACT
...
I am wondering how can I select all cars in the database of a certain class? Perhaps, I want to know how many cars of each class exists?
I can write a query like this.
SELECT COUNT(*) FROM CARS WHERE (MAKE, MODEL) IN (SELECT MAKE, MODEL FROM CLASSES WHERE CLASS = 'SUV')
The problem here, I wont actually be able to deal with NULLs in my data. I want to say that all models of JEEP are SUVs, or any MAKE car that's called CUBE would be a compact car.
Could this be done assuming there are no conflicts? Can I have a priority set up, like All Porches are CARS except the Cayenne which is an SUV by doing something like this:
MAKE, MODEL, CLASS
PORCHE, NULL , CAR
PORCHE, CAYENNE, SUV
If this isn't possible with MySQL, is there a better DB technology out there that would be good at this. Lets assume that The CLASSES Table would Contain 50K+ Rows and The CARS Table would contain 5M+ Rows. I am looking for a fast way of performing such a query in the database, and not needing to fetch millions of rows to process in a script? Also What if its not just Make and Model, but also sub-model, engine, etc..
Also, I simplified the data quite a bit, there are 4 levels of hierarchy.
Assuming that make and model cannot be both null for a given class. You can use the ifnull() function in MySQL:
select cl.class, count(*)
from cars c inner join class cl
on c.make = ifnull(cl.make,c.make)
and c.model=ifnull(cl.model,c.model)
group by cl.class
You may want to add an index on columns makes and model for faster access. Since classes have fewer rows using an inner join (as above) will restrict the number of rows returned.
You can write your query like this:
SELECT COUNT(*)
FROM CARS c join
classes cl
on (c.make = cl.make or cl.make is null) and
(c.model = cl.model or cl.model is null) and
cl.class = 'SUV'
The problem is that you might get duplicates. So the better count starts with:
select count(distinct c.vin)
. . .
This should work for the two cases you gave, for JEEP and CUBE.
SELECT s.class, COUNT(*)
FROM car c, car_class s
WHERE c.make = s.make
AND c.model = s.model
GROUP BY s.class
should give you something like
SUV 14
COMPACT 32
TRUCK 11
etc.

Query MySQL for rows that share a value, and returning them as columns?

This is for a homework assignment. I haven't copy-pasted the question below, I made an simpler version of it that focuses on the specific area where I'm stuck.
Let's say I have a table of two values: a person's name, and the place he had lunch yesterday. Assume everyone has lunch in pairs. How can I query the database to return all the pairs of people that had lunch together yesterday? Each pair must be only listed once.
I'm actually not even sure what the professor means by return them as pairs. I've sent him an email, but no reply yet. It seems like he wants me to write a query that returns a table with column 1 as person 1 and column 2 as person 2.
Any suggestions on how to go about this? Does it seem right to assume he wants them as separate columns?
So far, I basically have:
SELECT name, restaurant FROM lunches GROUP BY restaurant, name
which essentially just reorganizes the table so that the people who had lunch together are one after the other.
We have to assume there can be only one pair eating lunch in a given restaurant.
You can get a list of pairs either using self-join:
SELECT l1.name, l2.name FROM lunches l1
JOIN lunches l2
ON l1.restaurant = l2.restaurant AND l1.name < l2.name
or using GROUP BY:
SELECT GROUP_CONCAT(name) FROM lunches
GROUP BY restaurant
The first query will return pairs in two different columns, while the second in one column, using comma as separator (default for GROUP_CONCAT, you can change it to whatever you wish).
Also note that for the first query names in pairs will come in alphabetical order as we use < instead of <> to avoid listing each pair twice.