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
これを機能させるにはどうすればよいですか?
現在のコードに基づくと、製品は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
;
質問のほかに、クエリの記述方法には潜在的な問題がたくさんあります。このクエリは、テーブル内の大きなデータではうまく機能しません。以下のオプションのいずれかを試してください。 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