SELECT
*,
p.name AS name,
p.image,
p.price,
(
SELECT ps.price
FROM product_special ps
WHERE p.id = ps.id
AND ps.date < NOW()
ORDER BY ps.priority ASC, LIMIT 1
) AS special_price,
(
SELECT ps.date
FROM product_special ps
WHERE p.id = ps.id
AND ps.date < NOW()
ORDER BY ps.priority ASC, LIMIT 1
) AS date
FROM product p LEFT JOIN product_special ps ON (p.id = ps.id)
ご覧のとおり、別の列を取得するためだけに同じサブクエリを繰り返しています。これを行うより良い方法はありますか?
idは両方のテーブルの主キーです。 product_special.priorityを一意にすることで問題が解決する場合は問題ありません。
組み合わせを想定product_special.id, product_special.priority
ユニークです
SELECT p.*, special_price,special_date
FROM product p
LEFT JOIN
(
SELECT ps.id, ps.price as special_price, ps.`date` as special_date
FROM product_special ps
INNER JOIN
(
SELECT id, MIN(priority) as min_priority
FROM product_special
GROUP BY id
) ps2
ON (ps2.id = ps.id)
)a ON (a.id=p.id)
フィールドをspecial_price.priceおよびdate.dateとして返すつもりでない限り、サブクエリ内の名前にエイリアスを付けないのはなぜですか?例えば.
_SELECT p.*, p.name AS name, p.image, p.price, ps.*
FROM product p
LEFT JOIN
(SELECT
psi.price as special_price, psi.date as my_date
FROM product_special psi
WHERE
p.id = psi.id AND
psi.date < NOW()
ORDER BY psi.priority ASC, LIMIT 1
) AS ps ON
p.id = ps.id
_
クエリ言語にFIRST()集約関数がありますか? product_specialのPKをIDと優先度の間の複合(両方のASCソート)にして、ORDER句を_GROUP BY id, psi.priority
_に変更できるかどうか不明
oRDER BY句を完全に削除してHAVING MIN(psi.priority)
を使用できる可能性があります
SQL Serverの「クロス適用」メカニズムはこれを解決しますが、PostgreSQLでは使用できないことに注意してください。基本的には、FROM句でテーブル式として呼び出される関数にパラメーター(現在のテーブル式の外部の列への参照になる傾向がある)を渡す方法のソリューションでした。ただし、別のレベルのサブクエリのネストや、FROM句からSELECT句への移動を回避する必要があるあらゆる種類の状況で役立ちます。 PostgreSQLは、一種の例外を作成することでこれを可能にしました。式が単純な関数呼び出しであるが、厳密には埋め込みSELECTでない場合は、そのようなパラメーターを渡すことができます。そう
left join highestPriorityProductSpecial(p.id) on true
大丈夫ですが、そうではありません
left join (select * from product_special ps where ps.id = p.id order by priority desc limit 1) on true
関数の定義はまさにそれです。
したがって、それは実際には便利な解決策です(少なくとも9.1では)。関数の内部で制限を行うことにより、最も優先度の高い行を抽出する関数を作成します。
しかし、関数には、クエリプランが関数の内部で何が行われているのかが表示されないという欠点があり、ネストされたループ結合が常に選択されると信じています。
Dezsoの回答に触発 https://dba.stackexchange.com/a/222471/1274 配列を使用して、PostgreSQLの問題を次のように解決しています:
SELECT
*,
p.name AS name,
p.image,
p.price,
(
SELECT ARRAY[ps.price, ps.date]
FROM product_special ps
WHERE p.id = ps.id
AND ps.date < NOW()
ORDER BY ps.priority ASC, LIMIT 1
) AS special_price_and_date
FROM product p LEFT JOIN product_special ps ON (p.id = ps.id)
確かにまだ1列だけですが、私のコードでは2つの値に簡単にアクセスできます。それもあなたのために働くことを願っています。
次のSQLコマンドを試してください。
SELECT p.name,p.image,p.price,pss.price,pss.date
FROM Product p OUTER APPLY(SELECT TOP(1)*
FROM ProductSpecial ps
WHERE p.Id = ps.Id ORDER BY ps.priority )as pss
これを最後の手段として、他の回答を1つ以上サポートしていないデータベースエンジンを使用するすべての人のためにここに置きます...
あなたは次のようなものを使うことができます:
SELECT (col1 || col2) as col3
(セパレータを使用するか、col1とcol2を特定の長さにフォーマットします。)その後、サブストリングを使用してデータを描画します。
私は誰かがそれが役に立つと思うことを望みます。
DB2 for z/OSでは、pack
関数とunpack
関数を使用して、副選択で複数の列を返します。
SELECT
*,
p.name AS name,
p.image,
p.price,
unpack((select PACK (CCSID 1028,
ps.price,
ps.date)
FROM product_special ps
WHERE p.id = ps.id
AND ps.date < NOW()
ORDER BY ps.priority ASC, LIMIT 1)) .* AS (SPECIAL_PRICE double, DATE date)
FROM product p LEFT JOIN product_special ps ON (p.id = ps.id);