简体   繁体   English

如何在左联接中返回多行

[英]How to return multiple rows in a LEFT JOIN

I have a situation where lets say i'm trying to get the information about some food. 我遇到一种情况,可以说我正在尝试获取有关某些食物的信息。 Then I need to display all the information plus all the ingredients in that food. 然后,我需要显示所有信息以及该食物中的所有成分。

With my query, i'm getting all the information in an array but only the first ingredient... 通过我的查询,我以数组的形式获取了所有信息,但只有第一个要素...

   myFoodsArr = 
        [0]
          foodDescription = "the description text will be here"
          ratingAverage = 0
          foodId = 4
          ingredient = 1
          ingAmount = 2
          foodName = "Awesome Food name"
          typeOfFood = 6
          votes = 0

I would like to get something back like this... 我想像这样回来

        myFoodsArr = 
            [0]
              foodDescription = "the description text will be here"
              ratingAverage = 0
              foodId = 4
              ingArr = {ingredient: 1, ingAmount: 4}, {ingredient: 3, ingAmount: 2}, {ingredient: 5, ingAmount: 1}
              foodName = "Awesome Food name"
              typeOfFood = 6
              votes = 0

This is the query im working with right now. 这是即时消息正在使用的查询。 How can I adjust this to return the food ID 4 and then also get ALL the ingredients for that food? 如何调整此值以返回食物ID 4,然后还获得该食物的所有成分? All while at the same time doing other things like getting the average rating of that food? 在同一时间做其他事情,例如获得该食物的平均评分吗?

Thanks! 谢谢!

   SELECT a.foodId, a.foodName, a.foodDescription, a.typeOfFood, c.ingredient, c.ingAmount, AVG(b.foodRating) AS ratingAverage, COUNT(b.foodId) as tvotes 
FROM `foods` a 
LEFT JOIN `foods_ratings` b 
   ON a.foodId = b.foodId 
LEFT JOIN `foods_ing` c 
   ON a.foodId=c.foodId 
WHERE a.foodId=4

EDIT: 编辑:

Catcall introduced this concept of "sub queries" I never heard of, so I'm trying to make that work to see if i can do this in 1 query easily. Catcall引入了我从未听说过的“子查询”这一概念,因此我正在尝试进行这项工作,以查看是否可以轻松地在1个查询中完成此操作。 But i just keep getting a return false. 但我只是不断得到错误的回报。 This is what I was trying with no luck.. 这就是我没有运气的尝试。

//I changed some of the column names to help them be more distinct in this example

SELECT a.foodId, a.foodName, a.foodDescription, a.typeOfFood, AVG(b.foodRating) AS ratingAverage, COUNT(b.foodId) as tvotes 
FROM foods a 
LEFT JOIN foods_ratings b ON a.foodId = b.foodId 
LEFT JOIN (SELECT fId, ingredientId, ingAmount 
                 FROM foods_ing 
                 WHERE fId = 4 
                 GROUP BY fId) c ON a.foodId = c.fId 
           WHERE a.foodId = 4";

EDIT 1 more thing related to ROLANDS GROUP_CONCAT/JSON Idea as a solution 4 this 编辑另外1条与ROLANDS GROUP_CONCAT / JSON Idea相关的内容作为解决方案4

I'm trying to make sure the JSON string im sending back to my Flash project is ready to be properly parsed Invalid JSON parse input. 我试图确保发送回我的Flash项目的JSON字符串已准备好正确解析Invalid JSON parse input. keeps popping up.. 不断弹出..

so im thinking i need to properly have all the double quotes in the right places. 所以我想我需要在正确的位置适当地包含所有双引号。

But in my MySQL query string, im trying to escape the double quotes, but then it makes my mySQL vars not work, for example... 但是在我的MySQL查询字符串中,我试图转义双引号,但是这样会使我的mySQL var无法工作,例如...

If i do this.. 如果我这样做..

GROUP_CONCAT('{\"ingredient\":', \"c.ingredient\", ',\"ingAmount\":', \"c.ingAmount\", '}')`

I get this... 我明白了...

{"ingredient":c.ingredient,"ingAmount":c.ingAmount},{"ingredient":c.ingredient,"ingAmount":c.ingAmount},{"ingredient":c.ingredient,"ingAmount":c.ingAmount}

How can i use all the double quotes to make the JSON properly formed without breaking the mysql? 如何在不破坏mysql的情况下使用所有双引号使JSON正确形成?

This should do the trick: 这应该可以解决问题:

SELECT    food_ingredients.foodId
,         food_ingredients.foodName
,         food_ingredients.foodDescription
,         food_ingredients.typeOfFood
,         food_ingredients.ingredients
,         AVG(food_ratings.food_rating) food_rating
,         COUNT(food_ratings.foodId)    number_of_votes 
FROM      (
           SELECT    a.foodId
           ,         a.foodName
           ,         a.foodDescription
           ,         a.typeOfFood
           ,         GROUP_CONCAT(
                         '{ingredient:', c.ingredient,
                     ,   ',ingAmount:', c.ingAmount, '}'
                     ) ingredients
           FROM      foods a 
           LEFT JOIN foods_ing c 
           ON        a.foodsId = c.foodsId 
           WHERE     a.foodsId=4
           GROUP BY  a.foodId
          ) food_ingredients
LEFT JOIN food_ratings
ON        food_ingredients.foodId = food_ratings.foodId
GROUP BY  food_ingredients.foodId 

Note that the type of query you want to do is not trivial in any SQL-based database. 请注意,您要执行的查询类型在任何基于SQL的数据库中都不是简单的。

The main problem is that you have one master (food) with two details (ingredients and ratings). 主要问题是您拥有一个具有两种详细信息(成分和等级)的主食(食物)。 Because those details are not related to each other (other than to the master) they form a cartesian product with each other (bound only by their relationship to the master). 因为这些细节彼此无关(除了与母版无关),所以它们彼此形成笛卡尔积(仅受它们与母版的关系约束)。

The query above solves that by doing it in 2 steps: first, join to the first detail (ingredients) and aggregate the detail (using group_concat to make one single row of all related ingredient rows), then join that result to the second detail (ratings) and aggregate again. 上面的查询通过以下两个步骤解决了这一问题:首先,连接到第一个详细信息(成分)并聚合详细信息(使用group_concat制作所有相关成分行的一行),然后将结果连接到第二个详细信息(评分)并再次汇总。

In the example above, the ingredients are returned in a structured string, exactly like it appeared in your example. 在上面的示例中,成分以结构化字符串的形式返回,就像在您的示例中出现的一样。 If you want to access the data inside PHP, you might consider adding a bit more syntax to make it a valid JSON string so you can decode it into an array using the php function json_decode() : http://www.php.net/manual/en/function.json-decode.php 如果要访问PHP内的数据,则可以考虑添加更多语法以使其成为有效的JSON字符串,以便可以使用php函数json_decode()将其解码为数组: http : json_decode() /manual/zh-CN/function.json-decode.php

To do that, simply change the line to: 为此,只需将行更改为:

CONCAT(
    '['
,   GROUP_CONCAT(
        '{"ingredient":', c.ingredient
    ,   ',"ingAmount":', c.ingAmount, '}'
    )
,   ']'
)

(this assumes ingredient and ingAmount are numeric; if they are strings, you should double quote them, and escape any double quotes that appear within the string values) (这假定ingredientingAmount为数字;如果它们是字符串,则应将其双引号,并转义出现在字符串值内的所有双引号)

The concatenation of ingredients with GROUP_CONCAT can lead to problems if you keep a default setting for the group_concat_max_len server variable. 如果您为group_concat_max_len服务器变量保留默认设置, group_concat_max_len成分与GROUP_CONCAT串联可能会导致问题。 A trivial way to mitigate that problem is to set it to the maximum theoretical size of any result: 减轻该问题的一种简单方法是将其设置为任何结果的最大理论大小:

SET group_concat_max_len = @@max_allowed_packet;

You can either execute this once after you open the connection to mysql, and it will then be in effect for the duration of that session. 打开与mysql的连接后,您可以执行一次此操作,然后在该会话期间有效。 Alternatively, if you have the super privilege, you can change the value across the board for the entire MySQL instance: 另外,如果您具有超级特权,则可以为整个MySQL实例全面更改值:

SET GLOBAL group_concat_max_len = @@max_allowed_packet;

You can also add a line to your my.cnf or my.ini to set group_concat_max_lenght to some arbitrary large enough static value. 您还可以在my.cnf或my.ini中添加一行以将group_concat_max_lenght设置为任意任意的足够大的静态值。 See http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_group_concat_max_len 参见http://dev.mysql.com/doc/refman/5.5/zh-CN/server-system-variables.html#sysvar_group_concat_max_len

One obvious solution is to actually perform two queries: 一种显而易见的解决方案是实际执行两个查询:

1) get the food 1)拿到食物

SELECT a.foodId, a.foodName, a.foodDescription, a.typeOfFood
FROM `foods` a
WHERE a.foodsId=4

2) get all of its ingredients 2)获取所有成分

SELECT c.ingredient, c.ingAmount
FROM `foods_ing` c
WHERE c.foodsId=4

This approach has the advantage that you don't duplicate data from the "foods" table into the result. 这种方法的优点是您不会将“食物”表中的数据复制到结果中。 The disadvantage is that you have to perform two queries. 缺点是您必须执行两个查询。 Actually you have to perform one extra query for each "food", so if you want to have a listing of foods with all their ingredients, you would have to do a query for each of the food record. 实际上,您必须对每种“食物”执行一个额外的查询,因此,如果要列出所有食物及其成分的清单,则必须对每个食物记录进行查询。

Other solutions usually have many disadvantages, one of them is using GROUP_CONCAT function, but it has a tough limit on the length of the returned string. 其他解决方案通常具有许多缺点,其中之一是使用GROUP_CONCAT函数,但是它对返回的字符串的长度有严格的限制。

When you compare MySQL's aggregate functions and GROUP BY behavior to SQL standards, you have to conclude that they're simply broken. 当您将MySQL的聚合函数和GROUP BY行为与SQL标准进行比较时,您必须得出结论,它们只是被破坏了。 You can do what you want in a single query, but instead of joining directly to the table of ratings, you need to join on a query that returns the results of the aggregate functions. 您可以在单个查询中执行所需的操作,但是您需要加入返回返回聚合函数结果的查询,而不是直接加入到评分表中。 Something along these lines should work. 遵循这些原则的东西应该起作用。

select a.foodId, a.foodName, a.foodDescription, a.typeOfFood, 
       c.ingredient, c.ingAmount,
       b.numRatings, b.avgRating
from foods a
left join (select foodId, count(foodId) numRatings, avg(foodRating) avgRating
           from foods_ratings
           group by foodId) b on a.foodId = b.foodId
left join foods_ing c on a.foodId = c.foodId
order by a.foodId

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM