SQL - Convert Many-Many Bridge Table to One-One Table - mysql

I am struggling at writing a query to get data from a table like this:
id food_id ingre_id
1 1 13
2 1 9
3 2 13
4 3 5
5 4 9
6 4 10
7 5 5
Assume in that table, each food only have 1 or 2 ingre ids. Then I want to have a table like this:
item_id ingre1_id ingre2_id
1 13 9
2 13 null //any food that have 1 ingre then set ingre2_id to null
3 5 null
4 9 10
5 5 null
Please suggest me a query to do such conversion. Thank you!

You can use aggregation. If you don't care about the ordering within a row:
select food_id, min(ingred_id) as ingred1_id,
(case when min(ingred_id) <> max(ingred_id) then max(ingred_id) end) as ingred2_id
from t
group by food_id;
Note: This use of min()/max() works specifically because you have two values. If you have more values, then ask another question with appropriate data.

This should produce what you asked for:
SELECT
a.`food_id` as `item_id`,
a.`ingre_id` as `ingre1_id`,
b.`ingre_id` as `ingre2_id`
FROM `food` a
LEFT JOIN `food` b
ON a.`id` <> b.`id` AND a.`food_id` = b.`food_id`
WHERE a.`id` < b.`id` OR b.`id` IS NULL
GROUP BY a.`food_id`

Related

Make a query to select a value from one column that is combined with all the values from another column

Imagine I have the following tables:
Numbers PK
1
2
3
4
5
6
7
8
9
10
Numbers FK 1
Numbers FK 2
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
1
10
1
8
8
10
4
7
3
4
9
1
6
3
9
4
6
5
6
I have the following tables: "Numbers PK" as Primary key and another 2 tables that are related one with each other that are foreign keys of Numbers.
I am trying to make a query to select the number(s) from the table "NumbersFK2" that are related with all the numbers of "Numbers PK".
As you can see in this example the solution would be 1 as 1 is related with 1-10 in the tables "Numbers FK1" and "Numbers FK2"
I have tried to solve and after some days I need some help as I don't know how could I do it. I appreciate the help. Thanks
We use dense_rank() to count the Numbers_PK in case they're not consecutive. Then we left join, group by and count(distinct Numbers_PK).
with t3 as (
select Numbers_PK
,dense_rank() over(order by Numbers_PK) as dns_rnk
from t
)
select Numbers_FK_2
from t3 left join t2 on t2.Numbers_FK_1 = t3.Numbers_PK
group by Numbers_FK_2
having count(distinct Numbers_PK) = max(dns_rnk)
Numbers_FK_2
1
Fiddle

Compare 2 views with different number of columns

I have 2 views with different number of columns. 1 of the views has been joined with another view that is why it has additional columns.
The first view has 113 records (View 2), while the updated view (View 1) has 130 columns. I would like to find out the number of records that are extra in View 1
.
View 1 View 2
A|B|C|D|E A|B|C
1 2 3 4 5 1 2 3
1 2 3 7 8
3 2 1 4 5 3 2 1
3 2 1 7 8
expected result :
1 2 3 7 8
3 2 1 7 8
Thanks.
You can get that extra records by using 'not in' or 'not exists' conditions
select * from view1 m where not exists (
select 1 from view2 u where (m.a=u.a and m.b=u.b and m.c=u.c)
You can change those conditions as per your requirement
With left join also will get the required result
select m.* from view1 m left join view2 u
(m.a=u.a and m.b=u.b and m.c=u.c)
where u.a is null and u.b is null and u.c is null
You shoul probably refactor your DB schema and data logic.
But just to resolve your weird requirements you can:
http://sqlfiddle.com/#!9/cf2c50/2
SELECT t.a, t.b, t.c, t.d, t.e
FROM (
SELECT v1.*, IF(#idx = concat(v1.a,v1.b,v1.c),1,0) `filter`,#idx := concat(v1.a,v1.b,v1.c)
FROM v1
INNER JOIN v2
ON v1.a=v2.a AND v1.b=v2.b AND v1.c=v2.c
ORDER BY v1.a,v1.b,v1.c
) t
WHERE t.`filter`=1;
It is not best example of query performance, but it should return expected result.

MySQL Group by week num w/ multiple date column

I have a table with columns similar to below , but with about 30 date columns and 500+ records
id | forcast_date | actual_date
1 10/01/2013 12/01/2013
2 03/01/2013 06/01/2013
3 05/01/2013 05/01/2013
4 10/01/2013 09/01/2013
and what I need to do is get a query with output similar to
week_no | count_forcast | count_actual
1 4 6
2 5 7
3 2 1
etc
My query is
SELECT weekofyear(forcast_date) as week_num,
COUNT(forcast_date) AS count_forcast ,
COUNT(actual_date) AS count_actual
FROM
table
GROUP BY
week_num
but what I am getting is the forcast_date counts repeated in each column, i.e.
week_no | count_forcast | count_actual
1 4 4
2 5 5
3 2 2
Can any one please tell me the best way to formulate the query to get what I need??
Thanks
try:
SELECT weekofyear(forcast_date) AS week_forcast,
COUNT(forcast_date) AS count_forcast, t2.count_actual
FROM
t t1 LEFT JOIN (
SELECT weekofyear(actual_date) AS week_actual,
COUNT(forcast_date) AS count_actual
FROM t
GROUP BY weekOfYear(actual_date)
) AS t2 ON weekofyear(forcast_date)=week_actual
GROUP BY
weekofyear(forcast_date), t2.count_actual
sqlFiddle
You have to write about 30 (your date columns) left join, and the requirement is that your first date column shouldn'd have empty week (with a count of 0) or the joins will miss.
Try:
SELECT WeekInYear, ForecastCount, ActualCount
FROM ( SELECT A.WeekInYear, A.ForecastCount, B.ActualCount FROM (
SELECT weekofyear(forecast_date) as WeekInYear,
COUNT(forecast_date) as ForecastCount, 0 as ActualCount
FROM TableWeeks
GROUP BY weekofyear(forecast_date)
) A
INNER JOIN
( SELECT * FROM
(
SELECT weekofyear(forecast_date) as WeekInYear,
0 as ForecastCount, COUNT(actual_date) as ActualCount
FROM TableWeeks
GROUP BY weekofyear(actual_date)
) ActualTable ) B
ON A.WeekInYear = B.WeekInYear)
AllTable
GROUP BY WeekInYear;
Here's my Fiddle Demo
Just in case someone else comes along with the same question:
Instead of trying to use some amazing query, I ended up creating an array of date_columns_names and a loop in the program that was calling this query, and for each date_column_name, performing teh asme query. It is a bit slower, but it does work

Sorting a column and setting the result to another column in MySql

I have a problem about a query. Let's say I have a table structure like this.
TABLE_A
Id - Standing - Point
1 null 8
2 null 9
3 null 12
4 null 11
5 null 4
When I sort this table by Point column(SELECT * FROM TABLE_A ORDER BY Point DESC), I want to update Standing column to be updated according to sort results. After sorting and setting these values to Standing column, the result that I want to have is this:
TABLE_A
Id - Standing - Point
1 4 8
2 3 9
3 1 12
4 2 11
5 5 4
Is it possible to do this? If yes, how?
Thanks in advance...
You can do this with the rather arcane syntax:
update table_A
set standing = (select cnt
from (select count(*) as cnt
from table_a a2
where a2.point >= table_A.point
)
)
The use of the nested select is simply a syntax convention required in MySQL.

MYSQL select query using count (*)

i have a problem concerning a select query in MYSQL
i have two different tables and i want to obtain a certain result
i used COUNT method which gave me only the results (>=1)
But in reality , i want to use all counts with zero included how to do it?
My query is:
SELECT
first.subscriber_id,
second.tag_id,
COUNT(*)
FROM
content_hits first
JOIN content_tag second ON first.content_id=second.content_id
GROUP BY
second.Tag_id,first.Subscriber_id<br>
First table:Content_hits
CONTENT_ID SUBSCRIBER_ID
30 1
10 10
34 4
32 2
40 3
28 3
30 6
31 8
12 3
Second table:Content_tag
CONTENT_ID TAG_ID
1 1
2 1
3 1
4 1
5 1
6 1
7 1
8 1
9 1
10 1
11 2
12 2
13 2
14 2
Result but incomplete For example:Subsrciber6 for tag_id=1 should have a count(*)=0
subscriber_id tag_id COUNT(*)
1 1 4
2 1 7
3 1 2
4 1 1
5 1 3
7 1 2
8 1 1
9 1 1
10 1 3
1 2 2
2 2 3
3 2 2
Now that you have further elaborated on what you actually want to achieve, it can be seen that the problem is much more complex. You actually want all combinations of subscriber_id and tag_id, and then count the number of actual entries in the joined table product. whew. So here goes the SQL:
SELECT combinations.tag_id,
combinations.subscriber_id,
-- correlated subquery to count the actual hits by tag/subscriber when joining
-- the two tables using content_id
(SELECT count(*)
FROM content_hits AS h
JOIN content_tag AS t ON h.content_id = t.content_id
WHERE h.subscriber_id = combinations.subscriber_id
AND t.tag_id = combinations.tag_id) as cnt
-- Create all combinations of tag/subscribers first, before counting anything
-- This will be necessary to have "zero-counts" for any combination of
-- tag/subscriber
FROM (
SELECT DISTINCT tag_id, subscriber_id
FROM content_tag
CROSS JOIN content_hits
) AS combinations
Not sure, but is this what you want?
SELECT first.subscriber_id, second.tag_id, COUNT(*) AS c
FROM content_hits first JOIN content_tag second ON first.content_id=second.content_id
GROUP BY second.Tag_id,first.Subscriber_id HAVING c = 0