Combining Data in Two Tables SQL - mysql

I'm sure a very basic question, but I'm continue to be stuck:
Table A - image_number, camera_type, total_sales
Table B - image_number, keyword
Table A has one ROW for each image_number - example:
image_number="AXJ789, camera_type="Nikon", total_sales=678
image_number="JIJ123", camera_type="Canon", total_sales=999
image_number="KNI908", camera_type="Sony", total_sales=565
Table B has many ROWs for each image_number - example:
image_number="AXJ789", keyword = "rain"
image_number="AXJ789", keyword = "mountain"
image_number="AXJ789", keyword = "grass"
image_number="AXJ789", keyword = "cloud"
What I'm trying to do is JOIN the two tables so that I can generate the following output:
image_number="AXJ789", camera_type=678, camera_type="Nikon", keyword(1) = "rain", keyword(2) = "mountain", keyword(3) = "grass", keyword(4) = "cloud"
In other words, I want to have all items in each ROW in table A + all the items from table B. For each image_number in Table A, there could be no "keywords" in Table B or 50 keywords - depends on the image.
When I do an INNER JOIN, of course I can get one "keyword" from table B, but I can't figure out how to get all of them.

You can concatenate the keywords together:
select a.*,
(select group_concat(b.keyword)
from b
where b.image_number = a. image_number
) as keywords
from a;
This creates a comma-delimited list of the keywords. This is much simpler (in MySQL) than trying to put them in separate columns. In fact, if you wanted separate columns, I might suggest parsing this result:
select a.*, -- or whatever columns you want
substring_index(keywords, ',' 1) as keyword1,
substring_index(substring_index(keywords, ',' 2), ',', -1) as keyword2,
substring_index(substring_index(keywords, ',' 3), ',', -1) as keyword3,
substring_index(substring_index(keywords, ',' 4), ',', -1) as keyword4
from a left join
(select b.image_number, group_concat(b.keyword) as keywords
from b
group by b.image_number
) b
on b.image_number = a. image_number;

You can generate a comma-separated list of keywords for each image using GROUP_CONCAT and JOIN (but use a LEFT JOIN if an image may have no keywords).
SELECT a.*, GROUP_CONCAT(b.keyword) AS keyword_list
FROM a
JOIN b on b.image_number = a.image_number
GROUP BY a.image_number
Output for your sample data:
image_number camera_type total_sales keyword_list
AXJ789 Nikon 678 rain,mountain,grass,cloud
Demo on dbfiddle
You can then parse this into an array in your application, for example in PHP (if you have read the row into $row):
$keywords = explode(',', $row['keyword_list']);
print_r($keywords);
Output:
Array
(
[0] => rain
[1] => mountain
[2] => grass
[3] => cloud
)

Related

How to find which values are not in a column from the list?(SQL) [duplicate]

This question already has an answer here:
Select values from a list that are not in a table
(1 answer)
Closed 2 years ago.
I have a list of values:
('WEQ7EW', 'QWE7YB', 'FRERH4', 'FEY4B', .....)
and the dist table with a dist_name column.
and I need to create SQL query which would return values from the list which don't exist in the dist_name column.
Yo need to use left join. This requires creating a derived table with the values you care about. Here is typical syntax:
select v.val
from (values ('WEQ7EW'), ('QWE7YB'), ('FRERH4'), ('FEY4B')
) v(val) left join
t
on t.col = v.val
where t.col is null;
Not all databases support the values() table constructor but allow allow some method for creating a derived table. In MySQL, this looks like:
select v.val
from (select'WEQ7EW' as val union all
select 'QWE7YB' as val union all
select 'FRERH4' as val union all
select 'FEY4B' as val
) v(val) left join
t
on t.col = v.val
where t.col is null;
You would typically put this list of values in a derived table, and then use not exists. In MySQL:
select v.dist_name
from (
select 'WEQ7EW' as dist_name
union all select 'QWE7YB'
union all ...
) v
where not exists (select 1 from dist d where d.dist_name = v.dist_name)
Or if you are running a very recent version (8.0.19 or higher), you can use the VALUES ROW() syntax:
select v.dist_name
from (values row('WEQ7EW'), row('QWE7YB'), ...) v(dist_name)
where not exists (select 1 from dist d where d.dist_name = v.dist_name)
SELECT TRIM(TRAILING ',' FROM result) result
FROM ( SELECT #tmp:=REPLACE(#tmp, CONCAT(words.word, ','), '') result
FROM words, (SELECT #tmp:='WEQ7EW,QWE7YB,FRERH4,FEY4B,') arg
) perform
ORDER BY LENGTH(result) LIMIT 1;
fiddle
The list of values to be cleared from existing values is provided as CSV string with final comma and without spaces before/after commas ('WEQ7EW,QWE7YB,FRERH4,FEY4B,' in shown code).
If CSV contains duplicate values all of them will be removed whereas non-removed duplicates won't be compacted. The relative arrangement of the values will stay unchanged.
Remember that this query performs full table scan, so it is not applicable to huge tables because it will be slow.

how to concatenate multiple rows into one

Using SQL 2008 R2
I have two tables and want to create a table like:
output
Input tables
input table 1
inout table 2
I have tried using stuff function as
SELECT o.DEPT_ID,o.CLIENT_ID,
code,
(STUFF((SELECT CAST(', ' + CODE AS VARCHAR(MAX))
FROM ORDERS
WHERE (o.FUNDER_ID = f.FUNDER_ID)
FOR XML PATH ('')), 1, 2, '')) AS funder_code
FROM FUNDERS f
join ORDERS o on o.FUNDER_ID=f.FUNDER_ID
where o.DEPT_ID=111 and CLIENT_ID='B001'
and I'm not getting the output.
First of all, your desired output appears to have the 'name' column from your second input table as a comma-separated list, but your code implies that you want the 'code' column concatenated instead. This solution concatenates the 'name' column.
Second, looking at your input tables, you can't directly use join ORDERS o on o.FUNDER_ID=f.FUNDER_ID because 'B0000000019' does not equal 'F19'. However, once you manipulate those columns so they could be joined, try this:
SELECT DISTINCT o.dept_id, o.client_id
,(STUFF((SELECT distinct CAST(', ' + name AS VARCHAR(MAX))
FROM FUNDERS f
JOIN ORDERS o2 ON o2.funder_id = f.funder_id
FOR XML PATH ('')), 1, 2, '')) AS funder_code
FROM ORDERS o

How to take more than one rows from condition?

I have 2 different tables. First contains the following columns: id, names and id_of_exec, the other: id_of_exec and name_of_exec. I want to join them, but I'm having a problem with the join condition:
ON (x.id_of_exec = y.id_of_exec AND ( y.name = "XYZ" OR y.name = "ABC"))
(Names - XYZ and ABC have different id_of_exec)
And there is problem because column id_of_exec has the same id_of_exec for more than one id and SQL shows me only y.name = "XYZ". How to get results of both XYZ + ABC. On the end I'm grouping by names because I need to get just names from 1st table where there are names from 2nd table XYZ + ABC.
I tried to use select behind AND but select returns more than 1 row.
ON (x.id_of_exec = y.id_of_exec )
where ( y.name = "XYZ" OR y.name = "ABC")
The above query will join only on id_of_exec and then filter the records based on the values "XYZ" or "ABC" .

Using column value as clause for IN MySql

I don't understand why this doesn't work, I have a column where I store values comma separated in my "Mysql" database then I want to join two tables to give me results. eg:
SELECT *
FROM users u INNER JOIN
groups g
ON u.id IN ( g.ownerId )
WHERE u.active='1' AND g.gid='15';
And the value of g.ownerId in this senerio is '175,178'.
For some reason this only returns the results from the join with ownerId 175. BUT if I manually enter the values ( 175, 178 ) in the IN clause BOTH rows show up. Why isn't it using both values in the ownerId column?
I have tried this to "separate" the values or force a "list" but it didn't work...
SELECT * FROM users u INNER JOIN groups g ON u.id IN ( SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(g.ownerId, ',', 1), ' ', -1) as x,
SUBSTRING_INDEX(SUBSTRING_INDEX(g.ownerId, ',', 2), ' ', -1) as y ) where g.groupId='15'
Has anyone experienced this before or know what to do?
It doesn't work because the in value consists of a list with a single element that happens to have a comma in it. It is equivalent to:
on uid = '175,178'
You can replace the logic with find_in_set():
on find_in_set(uid, g.id) > 0
However, you really should learn about junctions tables and why your data structure is bad, bad, bad:
You are storing numbers as strings.
You have foreign key relationships with no way to declare them.
You are using string operations inappropriately.
Your query cannot make use of an index.
Fix the data structure.

Select JOINed substring

Is there some way to JOIN on a resulting substring?
I've got a query that looks like this:
SELECT _atc_codes.se, _atc_codes.code, SUBSTR(_atc_codes.code, 1, 1)
FROM diagnoses
JOIN _atc_codes
ON (_atc_codes.id = diagnoses.atc_code)
Now I want to add an extra column to this query which should be SUBSTR(_atc_codes.code, 1, 1) joined to its corresponding _atc_codes.se, how do I do that?
This image shows incorrect results, the 4th column should read "Matsmältningsorgan och ämnesomsättning" (corresponding cell in _atc_codes.se).
SQL Fidde: http://www.sqlfiddle.com/#!2/6695d
Can you try (this example uses MySQL user defined variables, it is important for this query that MySQL knows to use a value outside from subquery for comparision)
SELECT _atc_codes.se, _atc_codes.code,
#code_substr:=SUBSTR(_atc_codes.code, 1, 1) AS code_substr,
(
SELECT se
FROM _atc_codes
WHERE code=#code_substr
LIMIT 1
) AS code_substr_se
FROM diagnoses
JOIN _atc_codes ON _atc_codes.id = diagnoses.atc_code
Or (this example assigns table alias to outer table which is used in subquery because you are using a table twice and MySQL does not know which table to reference in SUBSTR in subquery):
SELECT outer_codes .se, outer_codes .code,
SUBSTR(outer_codes .code, 1, 1) AS code_substr,
(
SELECT se
FROM _atc_codes
WHERE code=SUBSTR(outer_codes.code, 1, 1)
LIMIT 1
) AS code_substr_se
FROM diagnoses
JOIN _atc_codes AS outer_codes ON outer_codes.id = diagnoses.atc_code
A third way would be adding a second JOIN and then group resultset like
SELECT _atc_codes_1st.se, _atc_codes_1st.code,
SUBSTR(_atc_codes_1st.code, 1, 1) AS code_substr,
MAX(_atc_codes_2nd.se) AS code_substr_se
FROM diagnoses
JOIN _atc_codes AS _atc_codes_1st ON _atc_codes_1st.id = diagnoses.atc_code
JOIN _atc_codes AS _atc_codes_2nd ON _atc_codes_2nd.code = SUBSTR(_atc_codes_1st.code, 1, 1)
GROUP BY _atc_codes_1st.se, _atc_codes_1st.code,code_substr
Deciding which variant to use, it would be the best to add a EXPLAIN to your query to show execution plan. Good luck.