web-dev-qa-db-ja.com

SELECTステートメントのMySQL一時列

MySQLクエリでいくつかの計算を行いたいのですが。計算に使用する一時的な列をいくつか作成しました。

現在動作している(ただし非推奨)SQLクエリのSQLフィドル: http://sqlfiddle.com/#!2/5dc99/14

MySQLのドキュメント9.4によると、ユーザー定義変数( http://dev.mysql.com/doc/refman/5.0/en/user-variables.html ): "SETステートメント以外の一般的な規則として、ユーザー変数に値を割り当てて、同じステートメント内で値を読み取らないでください。"

SELECT
  /** Product details **/
  product.id AS product_number,
  product.name AS product_name,

  /** Price details **/
  @redemption_price := product.redemption_price AS redemption_price,
  @customer_price_increment := (
    CASE
      (SELECT COUNT(1) FROM customer_price_increment AS cpi WHERE cpi.product_id = product.id AND cpi.customer_id = 4)
    WHEN 0 THEN
      0
    ELSE 
      @redemption_price * (SELECT cpi.increment_percentage / 100 FROM customer_price_increment AS cpi WHERE cpi.customer_id = 4 AND cpi.product_id = product.id)
    END
  ) AS customer_price_increment,
  @general_price_increment := (
    CASE
      (SELECT COUNT(1) FROM general_price_increment AS gpi WHERE gpi.product_id = product.id)
    WHEN 0 THEN
      0
    ELSE 
      @redemption_price * (SELECT gpi.increment_percentage / 100 FROM general_price_increment AS gpi WHERE gpi.product_id = product.id)
    END
    ) AS general_price_increment,
  @sale_price := @redemption_price + (
    CASE
      @customer_price_increment
    WHEN 0 THEN
      @general_price_increment
    ELSE
      @customer_price_increment
    END
  ) AS sale_price
FROM
  product

$ 250を超える商品価格の商品のみを表示するには、HAVING sale_price> 250を追加します。

HAVING sale_price> 250の追加は、ユーザー定義変数の使用法が原因で機能しません( http://sqlfiddle.com/#!2/5dc99/19 を参照)。

ユーザー定義変数をできる限り削除しましたが、すべてのユーザー定義変数がないと機能しません。 http://sqlfiddle.com/#!2/5dc99/24 HAVING句がないため、結果が表示されます。 http://sqlfiddle.com/#!2/5dc99/2 250ドルを超える価格の製品があるため、本来は結果が表示されません。

一時的な列は再利用できないため、ユーザー定義変数をすべて削除しても問題は解決しません( http://sqlfiddle.com/#!2/5dc99/25 )。 Unknown column 'general_price_increment' in 'field list'

SELECT
  /** Product details **/
  product.id AS product_number,
  product.name AS product_name,

  /** Price details **/
  product.redemption_price AS redemption_price,
  product.redemption_price * (
    CASE
      (SELECT COUNT(1) FROM customer_price_increment AS cpi WHERE cpi.product_id = product.id AND cpi.customer_id = 4)
    WHEN 0 THEN
      0
    ELSE 
      (SELECT cpi.increment_percentage / 100 FROM customer_price_increment AS cpi WHERE cpi.customer_id = 4 AND cpi.product_id = product.id)
    END
  ) AS customer_price_increment,
  product.redemption_price * (
    CASE
      (SELECT COUNT(1) FROM general_price_increment AS gpi WHERE gpi.product_id = product.id)
    WHEN 0 THEN
      0
    ELSE 
      (SELECT gpi.increment_percentage / 100 FROM general_price_increment AS gpi WHERE gpi.product_id = product.id)
    END
    ) AS general_price_increment,
  redemption_price + (
    CASE
      customer_price_increment
    WHEN 0 THEN
      general_price_increment
    ELSE
      customer_price_increment
    END
  ) AS sale_price
FROM
  product
HAVING
  sale_price > 250

これを機能させるにはどうすればよいですか?

3
Ivo van Beek

現在のコードに基づくと、製品はcustomer_price_incrementまたはgeneral_price_incrementのいずれかで最大1つの一致を持つことができます。その事実を念頭に置いて、私はおそらく別のアプローチを試みます。

まず、次のようにすべての価格を返す基本クエリを書き換えます。

SELECT
  p.id AS product_number,
  p.name AS product_name,
  p.redemption_price,
  COALESCE(p.redemption_price * cpi.increment_percentage / 100, 0) AS customer_price_increment,
  COALESCE(p.redemption_price * gpi.increment_percentage / 100, 0) AS general_price_increment,
  p.redemption_price * (1 + COALESCE(cpi.increment_percentage, gpi.increment_percentage, 0) / 100) AS sale_price
FROM product AS p
LEFT JOIN customer_price_increment AS cpi ON cpi.id = p.id AND cpi.customer_id = 4
LEFT JOIN general_price_increment AS gpi ON gpi.id = p.id

sale_priceでフィルタリングするには、上記のクエリを派生テーブルとして使用するだけで、sale_priceエイリアスを参照し、WHERE句で式全体を繰り返さないようにすることができます。

SELECT *
FROM (
    SELECT
      p.id AS product_number,
      p.name AS product_name,
      p.redemption_price,
      COALESCE(p.redemption_price * cpi.increment_percentage / 100, 0) AS customer_price_increment,
      COALESCE(p.redemption_price * gpi.increment_percentage / 100, 0) AS general_price_increment,
      p.redemption_price * (1 + COALESCE(cpi.increment_percentage, gpi.increment_percentage, 0) / 100) AS sale_price
    FROM product AS p
    LEFT JOIN customer_price_increment AS cpi ON cpi.id = p.id AND cpi.customer_id = 4
    LEFT JOIN general_price_increment AS gpi ON gpi.id = p.id
) AS s
WHERE sale_price > 250
;

最初のクエリをビューにして、必要に応じて結果からフィルターをかけることもできます。

SELECT *
FROM sale_prices_view
WHERE sale_price > 250
;
2
Andriy M

質問のほかに、クエリの記述方法には潜在的な問題がたくさんあります。このクエリは、テーブル内の大きなデータではうまく機能しません。以下のオプションのいずれかを試してください。 1つはネストされた選択なし、2つ目はネストされた選択あり。クエリの下の各テーブルに適切なインデックスがあると仮定すると、クエリは適切ではるかに読みやすくなります。

ネストされた選択ステートメントなし

    SELECT
      /** Product details **/
            t1.product_id           AS product_number
            ,t1.name                AS product_name

      /** Price details **/
            ,t1.redemption_price    AS redemption_price

            ,CASE WHEN t1.product_id=t2.product_id AND t2.customer_id=4 
                    THEN ( (t2.increment_percentage/100) * t1.redemption_price)
                    ELSE 0 
            END AS customer_price_increment

            ,CASE WHEN t1.product_id=t3.product_id 
                    THEN ( (t3.increment_percentage/100) * t1.redemption_price)
                    ELSE 0
            END AS general_price_increment

            ,CASE WHEN --customer_price_increment
                    (CASE WHEN t1.product_id=t2.product_id AND t2.customer_id=4 
                        THEN ( (t2.increment_percentage/100) * t1.redemption_price)
                        ELSE 0 
                    END)=0
                    THEN 0
                    ELSE --general_price_increment
                        (CASE WHEN t1.product_id=t3.product_id 
                                THEN ( (t3.increment_percentage/100) * t1.redemption_price)
                                ELSE 0
                        END)
            END AS sale_price
    FROM product t1
    FULL OUTER JOIN customer_price_increment t2
        ON t1.product_id=t2.product_id
        AND t2.customer_id=4
    FULL OUTER JOIN general_price_increment t3
        ON t1.product_id = t3.product_id
    WHERE 
            (CASE WHEN --customer_price_increment
                    (CASE WHEN t1.product_id=t2.product_id AND t2.customer_id=4 
                        THEN ( (t2.increment_percentage/100) * t1.redemption_price)
                        ELSE 0 
                    END)=0
                    THEN 0
                    ELSE --general_price_increment
                        (CASE WHEN t1.product_id=t3.product_id 
                                THEN ( (t3.increment_percentage/100) * t1.redemption_price)
                                ELSE 0
                        END)
            END) > 250

ネストされたselect stmtを使用

    SELECT 
            product_number
            ,product_name
            ,redemption_price
            ,customer_price_increment
            ,general_price_increment
            ,CASE WHEN customer_price_increment = 0 
                    THEN general_price_increment  
                    ELSE customer_price_increment 
            END AS sale_price
    FROM
    (
        SELECT
          /** Product details **/
                t1.product_id           AS product_number
                ,t1.name                AS product_name

          /** Price details **/
                ,t1.redemption_price    AS redemption_price

                ,CASE WHEN t1.product_id=t2.product_id AND t2.customer_id=4 
                        THEN ( (t2.increment_percentage/100) * t1.redemption_price)
                        ELSE 0 
                END AS customer_price_increment

                ,CASE WHEN t1.product_id=t3.product_id 
                        THEN ( (t3.increment_percentage/100) * t1.redemption_price)
                        ELSE 0
                END AS general_price_increment

                ,CASE WHEN --customer_price_increment
                        (CASE WHEN t1.product_id=t2.product_id AND t2.customer_id=4 
                            THEN ( (t2.increment_percentage/100) * t1.redemption_price)
                            ELSE 0 
                        END)=0
                        THEN 0
                        ELSE --general_price_increment
                            (CASE WHEN t1.product_id=t3.product_id 
                                    THEN ( (t3.increment_percentage/100) * t1.redemption_price)
                                    ELSE 0
                            END)
                END AS sale_price
        FROM product t1
        FULL OUTER JOIN customer_price_increment t2
            ON t1.product_id=t2.product_id
            AND t2.customer_id=4
        FULL OUTER JOIN general_price_increment t3
            ON t1.product_id = t3.product_id
    )qry1
    WHERE 
            (CASE WHEN customer_price_increment = 0 
                    THEN general_price_increment  
                    ELSE customer_price_increment 
            END) > 250
1
Anup Shah