2

食べ物に関する情報を取得しようとしているとしましょう。次に、すべての情報に加えて、その食品のすべての材料を表示する必要があります。

私のクエリでは、すべての情報を配列で取得していますが、最初の材料のみを取得しています...

   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

このようなものを取り戻したいのですが...

        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

これは、現在使用しているクエリです。これを調整して食品ID4を返し、その食品のすべての材料を取得するにはどうすればよいですか?同時に、その食品の平均評価を取得するなどの他のことをしていますか?

ありがとう!

   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

編集:

Catcallは、私が聞いたことのない「サブクエリ」のこの概念を導入したので、1つのクエリでこれを簡単に実行できるかどうかを確認するためにそれを機能させようとしています。しかし、私はただreturnfalseを取得し続けます。これは私が運が悪かったのです。

//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";

解決策としてROLANDSGROUP_CONCAT/JSONアイデアに関連するもう1つのことを編集します4これ

Flashプロジェクトに送り返すJSON文字列が適切に解析される準備ができていることを確認しようとしていInvalid JSON parse input.ます。ポップアップが表示され続けます。

ですから、適切な場所にすべての二重引用符を適切に配置する必要があると考えています。

しかし、私のMySQLクエリ文字列では、二重引用符をエスケープしようとしていますが、mySQL変数が機能しなくなります。たとえば...

私がこれをするなら..

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

私はこれを手に入れます...

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

すべての二重引用符を使用して、mysqlを壊さずにJSONを適切に形成するにはどうすればよいですか?

4

3 に答える 3

1

これでうまくいくはずです:

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 

実行するクエリの種類は、SQL ベースのデータベースでは簡単ではないことに注意してください。

主な問題は、1 つのマスター (食品) と 2 つの詳細 (成分と評価) があることです。これらの詳細は (マスター以外では) 相互に関連していないため、相互にデカルト積を形成します (マスターとの関係によってのみ拘束されます)。

上記のクエリは、2 つのステップでそれを実行することで解決します。まず、最初の詳細 (成分) に結合し、詳細を集計し (group_concat を使用して、関連するすべての成分行の 1 つの行を作成します)、次にその結果を 2 番目の詳細に結合します (評価)、再度集計します。

上記の例では、例に表示されているのとまったく同じように、成分が構造化された文字列で返されます。PHP 内のデータにアクセスする場合は、もう少し構文を追加して有効な JSON 文字列にすることを検討してください。これにより、php 関数を使用して配列にデコードできますjson_decode(): http://www.php.net/manual/ en/function.json-decode.php

これを行うには、単に行を次のように変更します。

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

ingredient(これはとが数値であることを前提としingAmountています。文字列の場合は、それらを二重引用符で囲み、文字列値内にある二重引用符をエスケープする必要があります)

サーバー変数GROUP_CONCATのデフォルト設定を維持すると、成分を連結すると問題が発生する可能性があります。group_concat_max_lenその問題を軽減する簡単な方法は、結果の理論上の最大サイズに設定することです。

SET group_concat_max_len = @@max_allowed_packet;

mysql への接続を開いた後にこれを 1 回実行すると、そのセッションの間有効になります。または、super 権限を持っている場合は、MySQL インスタンス全体の値を全面的に変更できます。

SET GLOBAL group_concat_max_len = @@max_allowed_packet;

my.cnf または my.ini に行を追加して、group_concat_max_lengtht を任意の十分に大きな静的値に設定することもできます。http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_group_concat_max_lenを参照してください。

于 2012-05-02T06:54:24.517 に答える
0

明らかな解決策の 1 つは、実際に 2 つのクエリを実行することです。

1) 食べ物を手に入れる

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

2) すべての成分を入手する

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

このアプローチには、「foods」テーブルのデータを結果に複製しないという利点があります。欠点は、2 つのクエリを実行する必要があることです。実際には、「食品」ごとに 1 つの追加クエリを実行する必要があるため、すべての食材を含む食品のリストが必要な場合は、食品レコードごとにクエリを実行する必要があります。

通常、他のソリューションには多くの欠点があります。そのうちの 1 つはGROUP_CONCAT関数を使用していますが、返される文字列の長さに厳しい制限があります。

于 2012-05-01T21:11:07.757 に答える
-1

MySQL の集計関数と GROUP BY の動作を SQL 標準と比較すると、それらは単純に壊れていると結論付けなければなりません。1 つのクエリで必要なことを実行できますが、評価のテーブルに直接結合するのではなく、集計関数の結果を返すクエリに結合する必要があります。これらの線に沿った何かが機能するはずです。

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
于 2012-05-02T00:42:33.600 に答える