group by a random not null entry - mysql

I have a table usercolor like this:
id | idUser | color
-----------------------
1 | 1 | red
2 | 1 | blue
3 | 2 | green
4 | 2 | blue
5 | 3 | null
6 | 3 | blue
7 | 4 | null
I would like to have for each idUser one random fitting color which is not null whenever possible. Like this:
idUser | color
---------------
1 | blue
2 | green
3 | blue
4 | null
I thought I could achieve it by
SELECT idUser, color FROM usercolor GROUP BY idUser
However, with this SQL it might happen that idUser 3 is mapped to null although there exists the color blue for that idUser. How could I prevent that?

If you want one random color per user, then a correlated subquery comes to mind:
select idUser,
(select uc.color
from usercolor uc
where uc.idUser = u.idUser and uc.color is not null
order by rand()
limit 1
) as color
from (select distinct idUser from usercolor) u -- you can use `users` here instead

Related

mysql linked tables, return null if not present in connecting table

I have 2 tables that have a many-to-many relation, using a 3rd table.
Table 1 colors:
____________
id | color |
____________
1 | red |
2 | blue |
3 | yellow |
4 | orange |
5 | green |
table 2 content: (Table content is not really relevant for the query, I add it for completeness.)
id | itemname
1 | item1
2 | item2
3 | item3
...
table 3 is the connecting table colors_content
id | content_id | color_id
1 | 1 | 1
2 | 1 | 2
3 | 1 | 5
4 | 2 | 1
5 | 3 | 1
6 | 4 | 4
I want to return all colors + a way to figure out which ones are already linked to the content_id I am querying, so as an example, so for item.id=1 the result should be:
colors.id | colors.color | colors_content.content_id
1 | red | 1 (this can be anything, like a boolean)
2 | blue | 1
3 | yellow | null
4 | orange | null
5 | green | 1
again: it is a many-to-many relation, I need to output exactly 1 of each color, with a way to know if the queries item is already linked to it.
I have tried joining in different ways but I can not seem to find the correct syntax that includes the null values for unlinked colors.
SELECT c.* FROM `colors` c left join colors_content cc on cc.color_id=c.id where cc.content_id=1
only returns the 3 linked colors for item 1, not the 2 others.
edit:
This quite convoluted query seems to do the trick (although I am unclear why the group statement will not randomly choose between the queried id and the 0 value), but I must be missing a more obvious solution:
select * from ( SELECT c.id , c.color, cc.content_id as present FROM colors c JOIN colors_content cc ON c.id=cc.color_id WHERE cc.content_id=7 UNION select id , color, 0 as present from colors) as resulttable group by color
Move the check for the content_id in the ON clause and then check if the color_id of colors_content is NULL.
SELECT c.id,
c.color,
cc.colorid IS NULL exists_for_content_id
FROM colors c
LEFT JOIN colors_content cc
ON cc.color_id = c.id
AND cc.content_id = 1;
(This assumes that (colors.id), (content.id) and (colors_content.content_id, colors_content.color_id) are not nullable and unique.)

MySQL order by index and then duplicates together

I want to have the rows sorted by ID and then have the duplicates appear sequentially.
Example:
id color
1 red
2 green
3 yellow
4 green
5 green
6 red
Expected:
id color
1 red
6 red
2 green
4 green
5 green
3 yellow
If you are on MySql 8.0+ you can use MIN() window function:
select t.id, t.color
from (
select *,
min(id) over (partition by color) minid
from tablename
) t
order by t.minid, id
For previous versions:
select t.* from tablename t
order by (select min(id) from tablename where color = t.color), id;
See the demo.
Results:
| id | color |
| --- | ------ |
| 1 | red |
| 6 | red |
| 2 | green |
| 4 | green |
| 5 | green |
| 3 | yellow |

MySQL: Joining two tables, but getting just the first value in second table

I have two tables that I am trying to join.
car_make Table:
id | name | color
---------------------------
12 | Tayota | red
13 | Ford | gray
15 | Tesla | red
17 | GM | blue
car_type table:
id | car_id | image_one | image_two | image_three
--------------------------------------------------------------------------
1 | 12 | tayota1.jpg | tayota2.jpg | tayota3.jpg
2 | 17 | gm1.jpg | gm2.jpg | gm3.jpg
3 | 12 | tayota3.jpg | tayota4.jpg | tayota5.jpg
4 | 13 | ford1.png | ford2.png | ford3.png
5 | 13 | ford4.png | ford5.png | ford6.png
I want to grab and display every row within car_make, and join the first image_one instance for each make.
For example, I would like it to output:
Row 1: Tayota, red, tayota1.jpg
Row 2: Ford, gray, ford1.jpg
Row 3: Tesla, red, NULL
Row 4: GM, blue, gm1.jpg
How would I structure this query?
Because you want the equivalent of a left join and only want one row, the easiest way might be a correlated subquery:
select cm.*,
(select ct.image_one
from car_type ct
where ct.car_id = cm.id
order by ct.id
limit 1
) as image_one
from car_make cm;
There are several ways you can do this. Here's one using a sub-query to ensure you're only selecting the 1st car type per car make
select * from car_make cm
left join car_type ct on ct.car_id = cm.id
and ct.id = (select min(id) from car_type ct2 where ct2.car_id = ct.car_id)

Data selected from three tables repeats itself

I have created three tables (cars,colors and brand) with mysql. I want to select data from the three tables but the data are being repeated.
Note: Please the car_ID in the colors and brands table references the car_ID column from cars table.
cars table
car_ID | type
1 | 300
2 | 200
colors table
id | color | car_ID
1 | red | 1
2 | blue | 1
3 | black| 2
4 | green| 2
brands
id | brand | car_ID
1 | BMW | 1
2 | cst | 1
3 | ash | 2
4 | golf | 2
SELECT
a.car_ID
b.color
c.brand
FROM
cars a
INNER JOIN
colors b
ON
a.car_ID=b.id
INNER JOIN
brands c
ON
a.car_ID=c.id
WHERE
a.Car_ID=1;
This repeats the needed data, this is what i receive
Car_ID | colors | brands
1 | red | BMW
1 | blue | cst
1 | red | BMW
1 | blue | cst
However, the data below is what i desire to receive
id | colors | brands
1 | red | BMW
1 | blue | cst
UPDATE
Sorry guys, I have updated my tables data and hope this time around it make sense.
Please what am I doing wrong in my query above. Thanks for helping.
(I typed this out.. then realised that I have no clue what you want to do... But I'll leave this out anyway)
Your tables aren't very well defined... here is my proposed table structure:
cars table
id | type_id | colour_id
1 | 1 | 1
2 | 2 | 4
Car type id
id | brand_id | name
1 | 1 | 300
2 | 1 | 200
Colours table
id | name
1 | Red
2 | Blue
3 | Black
4 | Green
Brands table:
id | name
1 | BMW
2 | cst
3 | ash
4 | golf
Query...
SELECT c.id as car_id, t.name as `type`, b.name as `brand`, co.name as `colour`
FROM cars c
INNER JOIN types t ON t.id = cars.type_id
INNER JOIN brands b ON b.id = t.brand_id
INNER JOIN colours co ON co.id = c.colour_id
It should return something like below
car_id | type | brand | colour
1 | 300 | BMW | Red
2 | 300 | BMW | Green
It's hard to guess from your question how everything works, but it seems like you might want ...
SELECT a.car_ID
b.color
c.brand
FROM cars a
INNER JOIN colors b ON a.car_ID=b.car_ID /* changed ON criterion */
INNER JOIN brands c ON a.car_ID=c.car_ID
WHERE a.Car_ID=1
I'm guessing that you use car_ID throughout to relate the tables to each other.

Count value from table column

first I have a table which is pivot looks like this
pivot_product_Id | productsxx_Id | category_Id | subcategory_Id | color_Id
---------------------------------------------------------------------------
1 | 1 | 1 | 1 | 1
2 | 1 | 1 | 1 | 2
3 | 3 | 1 | 1 | 3
4 | 4 | 1 | 2 | 4
5 | 4 | 1 | 2 | 5
6 | 2 | 2 | 4 | 6
7 | 5 | 2 | 5 | 7
and I have color table like this
color_Id | color | color2
------------------------------------------
1 | black | white
2 | blue | orange
3 | white | black
4 | purple | black
5 | black | green
6 | red | black
and my question is in category ID 1 or 2 ... how many black color exist ? Counting from both color and color2 columns
and I tryed something like this but not geting the result I want and need help to create right query.
if(isset($shoes_post_var) || isset($nightwear_post_var)|| isset($outwear_post_var)){
$query3 = "SELECT count(*)
FROM pivot
JOIN category ON
pivot.category_Id = category.category_Id
JOIN subcategory ON
pivot.subcategory_Id = subcategory.subcategory_Id
JOIN color ON
pivot.color_Id = color.color_Id
JOIN productsxx ON
pivot.productsxx_Id = productsxx.productsxx_Id
WHERE
color IN ('$black')
or
color2 IN ('$black')
AND
category IN ('$shoes_post_var','$nightwear_post_var','$outwear_post_var')
GROUP BY pivot.color_Id ASC ";
$query5 = mysql_query($query3)or die(mysql_errno());
$total = mysql_result($query5, 0);
echo ' '.'('.$total.')';}
A possible solution
SELECT COUNT(*) total
FROM pivot
WHERE category_id IN (1, 2)
AND color_id IN
(
SELECT color_id
FROM color
WHERE color = 'black'
OR color2 = 'black'
)
Here is SQLFiddle demo
You only described two tables and asked about a query based on these two tables. This is a matter of a simple join with a simple selection - and a count - something like this:
SELECT count(1)
FROM pivot
JOIN color ON (pivot.color_id=color.color_id AND 'black' in (color.color, color.color2))
WHERE pivot.category_id = 1
Feel free to change the where clause for other categories.
However your existing code joins 5 tables and uses some other selection criteria. You really do need to ask the right question. Don't try to ask one thing while implying another.