2016-04-12 5 views
0

I have these two tables:私のデータベースは、私は私の総収益を示してクエリを実行しようとしている大きいですが、クエリはこれらのみ2を含み、それらは主キー「Id_TipoMed」と外部キー「TipoMedicamento_FK」によって関連しているカテゴリごとにグループ化された単一のクエリで複数の集計関数を使用して関連する値を返すようにMySQLに指示するにはどうすればよいですか?

このタイプの医薬品(「Tipo Medicamento」)はカテゴリと呼ばれています。また、カテゴリーごとに1つずつ表示したいと考えています(この場合は、「cantidad」と「precio」)それは、カテゴリごとの合計の占めるパーセンテージを示し、私はこのコードをした後、最大の利益とを:

SELECT 
    T.Id_TipoMed, 
    M.Nombre, 
    MAX(Cantidad*Precio) Ganancia_Medicamento, 
    SUM(Cantidad*Precio)Ganancia_Neta, 
    CONCAT(MAX(Cantidad*Precio)*100/SUM(Cantidad*Precio),'%') Porcentaje_Respecto_Tipo 
FROM Medicamento M 
    INNER JOIN TipoMedicamento T ON M.TipoMedicamento_FK=T.Id_TipoMed 
GROUP BY TipoMedicamento_FK 
HAVING 
    SUM(Cantidad*Precio) = (
     SELECT 
      SUM(Cantidad*Precio) 
     FROM Medicamento M2 
     WHERE M2.TipoMedicamento_FK=T.Id_TipoMed) 
    AND 
    MAX(Cantidad*Precio) = (
     SELECT 
      MAX(Cantidad*Precio) 
     FROM Medicamento M2 
     WHERE M2.TipoMedicamento_FK=T.Id_TipoMed); 

クエリで私の唯一の問題は、それが私の株式会社を示すことです私は間違って何をしているのですか?複数の集約関数を含まない複雑ではないクエリを実行するときに、過去にそのようにサブクエリを実行することによって、最大収益に関連付けられた名前に対応しません。

ありがとうございました!

答えて

0

GROUP BY句のSELECTリストの非集計式(GROUP BY句には表示されません)は不定です。非集約に対して返される値が、MAX()などの集約関数によって返される行の値に関連付けられた値になるという保証はありません。

MySQL以外のデータベースでは、M.Nombreという式がSELECTリストに含まれていると、その式はGROUP BYにも表示されないため、エラーが返されます。

MySQLは、MySQL特有のGROUP BY拡張機能の拡張のために、この文に対してエラーを返しません。これは文書化された動作です.MySQLリファレンスマニュアルで説明しています。 (この非標準的な動作は、このMySQLの癖に慣れていないSQL作成者のための「つかまえ」です。)

[MySQLをSQL標準によく適合させることができます。文は `Tipo_Medicamento`テーブルへの参加を含み、なぜsql_modeのでONLY_FULL_GROUP_BYを含むことによって、このクエリ、。)


は、それは明らかではありません。それは不要です。

`id_tipomed`がテーブルの主キーであるとすると、最大で1つの特定の値を持つ行が存在するため、結合は行を複製しません。そして、 `cantidad`と` precio`への無限定の言及は `Medicamento`テーブルのカラムへの参照であることが分かります。 (もしそれらが修飾されていれば、読者はテーブル定義を見て、どのテーブルに入っているのかを判断する必要はありませんでした)

ジョイン述語の等価比較は、 `tipomedicamento_fk`カラムにNULL値を持っています。しかし、ジョイン操作なしで、より効率的に行うことができます。

データベースが外部キー制約を強制しているかどうか、つまり、テーブル内の行を参照していない値を `tipomedicamento_fk`で期待しているかどうかはわかりません。存在する場合、結合操作はそれらを除外します。

それ以外では、結合操作の理由がないようです。

HAVING句は、MAX()およびSUM()集計によって返されるNULL値を持つ行を除外する必要がある方法よりも複雑に思えます。 MAX(foo)集約で返される値がnullでない場合、SUM(foo)の値はNULLでないことが保証されています。

このクエリからの復帰は、元からのリターンに相当する:

SELECT m.tipomedicamento_fk 
    , m.nombre 
    , MAX(m.cantidad*m.precio) AS `Ganancia_Medicamento` 
    , SUM(m.cantidad*m.precio) AS `Ganancia_Neta` 
    , CONCAT(MAX(m.cantidad*m.precio)*100/SUM(m.cantidad*m.precio),'%') 
     AS `Porcentaje_Respecto_Tipo` 
    FROM Medicamento m 
WHERE m.tipomedicamento_fk IS NOT NULL 
GROUP 
    BY m.tipomedicamento_fk 
HAVING `Ganancia_Medicamento` IS NOT NULL 

m.nombre発現のために戻り値は不定です。我々はそれがグループの行からの価値であることに気づいているが、特定の行であることは保証されていない。

`m.cantidad * m.precio`式の最大値を持つ行から値を返す場合は、SQLを別に書く必要があります。

使用できるパターンがいくつかあります。

1つの列を返すので、SELECTリストに相関サブクエリを使用できます。 ORDER BYを使用して "cantidad * precio"の最高値を最初に取得し、LIMIT 1を指定すると、1行だけが返されます。

SELECT m.tipomedicamento_fk 
    , (SELECT o.nombre 
      FROM Medicamento o 
      WHERE o.tipomedicamento_fk = m.tipomedicamento_fk 
      ORDER 
      BY (o.cantidad*o.precio) DESC 
       , o.nombre DESC 
      LIMIT 1 
     ) AS `nombre` 
    , MAX(m.cantidad*m.precio) AS `Ganancia_Medicamento` 
    , SUM(m.cantidad*m.precio) AS `Ganancia_Neta` 
    , CONCAT(MAX(m.cantidad*m.precio)*100/SUM(m.cantidad*m.precio),'%') 
     AS `Porcentaje_Respecto_Tipo` 
    FROM Medicamento m 
WHERE m.tipomedicamento_fk IS NOT NULL 
GROUP 
    BY m.tipomedicamento_fk 
HAVING `Ganancia_Medicamento` IS NOT NULL 

これは唯一の方法ではありません。同等の結果を返す他のクエリパターンがあります。

+0

このような完全な答えをありがとう! ^^ –

0

同じTipoMedicamento_FKを持つMedicamentoの行が複数ある可能性はありますか?その場合、TipoMedicamento_FKでグループ化すると、group by文の一部ではない列に対して正確な値が生成されるとは限りません。これを確認するには、クエリを実行して各TipoMedicamento_FK値の発生回数をカウントし、重複がないことを確認してください。

TipoMedicamento_FK値が重複している場合は、group by文に別の列を追加する必要があります。たとえば、NombreとTipoMedicamento_FKでグループ化することができます。

+0

私はそれを考慮していませんでした。はい、複数の行が同じTipoMedicamento_FKを参照しています。 –

関連する問題