So, I have two tables, one of which is like this:
Table: data
id | col_1 | col_2 | col_3 | col_4
------------------------------------------------------
1 | 167 | 12 | 15 | something1
2 | 198 | 27 | 12 | something2
3 | 253 | 15 | 17 | something3
and Table: catalog
id | col_1
-----------------
12 | red
15 | yellow
17 | pink
27 | green
Now, what I am trying to do is get col_1, col_2, col_3 and col_4 from the data table, but instead of getting the values of col_2 and col_3, these should be replaced by the col_1 of the catalog table, according to the catalog id.
For example, I want it to return, for every row of the data table, the following info:
167 | red | yellow | something1
198 | green | red | something2
253 | yellow | pink | something3
I tried this:
SELECT data.col_1, catalog.col_1, catalog.col_1, data.col_4
FROM data
INNER JOIN catalog ON data.col_2 = catalog.id
INNER JOIN catalog ON data.col_3 = catalog.id
but to no effect and surprise.
I simply can't find how to inner join multiple columns of one table to a single column of another, and Google has not been of great help. I actually don't know if I am searching with the right keywords.
You have to give the tablenames an alias, because it doesn't know where catalog refers to.
SELECT data.col_1, c1.col_1, c2.col_1, data.col_4
FROM data
INNER JOIN catalog c1 ON data.col_2 = c1.id
INNER JOIN catalog c2 ON data.col_3 = c2.id
Related
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.)
So I have this following table options lets say it contains three columns :
--------------------------
--------- options --------
--------------------------
id | name | category
--------------------------
1 | blue | 1
2 | red | 1
3 | a | 2
4 | b | 2
5 | c | 2
6 | 99 | 3
--------------------------
Now, I already have the following query to create a table containing three columns as a combination from table above :
SELECT T1.name, T2. name, T3.name
FROM (options T1 JOIN options T2 ON (T1.name > T2.name AND T1.category != T2.category))
LEFT JOIN options T3
ON (T3.name < T2.name AND T3.name < T1.name AND T3.category != T1.category AND T3.category != T2.category);
The results from running above query will return the following table (which is incorrect):
--------------------------
------ combinations ------
--------------------------
name | name | name
--------------------------
blue | a | 99
red | a | 99
blue | b | 99
red | b | 99
blue | c | 99
red | c | 99
red | 99 | NULL
blue | 99 | NULL
a | 99 | NULL
b | 99 | NULL
c | 99 | NULL
--------------------------
The resulting table should look as follows:
--------------------------
------ combinations ------
--------------------------
name | name | name
--------------------------
blue | a | 99
red | a | 99
blue | b | 99
red | b | 99
blue | c | 99
red | c | 99
--------------------------
The problem is whenever there is 3 different categories in the options the combination will also return the third name column including NULL values, and we don't want that.
I want the resulting combinations table to always have 3 column, and if there is only one category only populates the first column in the combinations table (the other columns should be null in this case), if there is two the first two columns as combinations (3rd column will be null), and if its three, all three columns have to have values respective to the options table (no null values).
Use cross join:
select *
from (select name
from options
where category = 1
) n1 cross join
(select name
from options
where category = 2
) n2 cross join
(select name
from options
where category = 3
) n3
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)
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.
Suppose a table fruits that looks like this:
------------------------------------------
| id | name | color | calories |
------------------------------------------
| 1 | apple | red | 20 |
| 2 | orange | orange | 10 |
| 3 | grapes | green | 5 |
| 4 | bananas | yellow | 15 |
| 5 | plum | purple | 25 |
------------------------------------------
How can I swap the values of a row, with another, leaving the id number intact?
Example:
SWAP ROW WITH ID "5" WITH ROW WITH ID "2"
Result:
------------------------------------------
| id | name | color | calories |
------------------------------------------
| 1 | apple | red | 20 |
| 2 | plum | purple | 25 |
| 3 | grapes | green | 5 |
| 4 | bananas | yellow | 15 |
| 5 | orange | orange | 10 |
------------------------------------------
Note that all the values are intact except for the id.
I need to do this with a really large list of values, so I need a one-liner, or at most, something that doesn't require the creation of temporary tables, and things like that.
Note: id is unique
Thank you
You could use a join inequality to line up the rows you want to swap:
update fruit a
inner join fruit b on a.id <> b.id
set a.color = b.color,
a.name = b.name,
a.calories = b.calories
where a.id in (2,5) and b.id in (2,5)
http://sqlfiddle.com/#!18/27318a/5
Since ID is unique, it is difficult to just swap the IDs, it's easier to swap the column contents. A query like this might be what you need:
UPDATE
yourtable t1 INNER JOIN yourtable t2
ON (t1.id, t2.id) IN ((1,5),(5,1))
SET
t1.color = t2.color,
t1.name = t2.name,
t1.calories = t2.calories
Please see fiddle here.
Here's a way to store values temporarily without using a temp table or a dummy row in your fruit table:
SELECT name, color, calories FROM fruit WHERE id = 2 INTO #name, #color, #calories;
UPDATE fruit AS f1, fruit AS f2
SET
f1.name = f2.name, f2.name = #name,
f1.color = f2.color, f2.color = #color,
f1.calories = f2.calories, f2.calories = #calories
WHERE (f1.id, f2.id) = (2, 5);
Here's another solution that uses a dummy id value:
UPDATE fruit SET id = 0 WHERE id = 5;
UPDATE fruit SET id = 5 WHERE id = 2;
UPDATE fruit SET id = 2 WHERE id = 0;
If your operations are based on ID, and you want to swap entire rows, a fancy way of swapping UNIQUE IDs is to start numbering them at 1, and use 0 as a temporary value.
Another way of performing this is using an unsigned column, and using a designated value (ie.: -1) for temporary. I wouldn't really recommend the latter, as we are effectively wasting space with this method. See http://dev.mysql.com/doc/refman/5.0/en/numeric-type-overview.html for more details.