2つの異なる解決策があります:(注:列挙型フィールドを「package_type」と呼びました)
最初の解決策(IF()関数を使用):
select
i.location,
if(ps.id is not null, ps.id, pg.id) as package_id
from
(select distinct location from Items) i
inner join
(select i.location, p.id
from Items i
inner join Packages p on (i.package_id = p.id and p.package_type = 'general')
) pg on (i.location = pg.location)
left join
(select i.location, p.id
from Items i
inner join Packages p on (i.package_id = p.id and p.package_type = 'special')
) ps on (i.location = ps.location)
このソリューションは、基本的に場所を取得し、それを一般的なパッケージに結合します(これは存在すると想定されているため、内部結合
)および特別なパッケージ(これはオプションです。したがって、 left join
)。次のようなレコードを作成します:
location | general-package | [special-package]
次に、MySQL IF
を使用します 最初に特別なパッケージのIDを選択しようとし、次に一般的なパッケージのIDにフォールバックする関数。
2番目の解決策(列挙型から整数へのキャストによる):
select i.location, p.id
from
(select i.location, max(cast(package_type as unsigned)) as package_type
from Items i
left join Packages p on (i.package_id = p.id)
group by location
) i
inner join
(select i.location, p.id, p.package_type
from Items i
inner join Packages p on (i.package_id = p.id)
) p on (i.location = p.location and i.package_type = p.package_type)
このソリューションは、列挙型が整数として格納されるという事実を利用しています。列挙型を整数にキャストします。 特別コード> この場合、
2
が返されます およびgeneral
1
を返します 。この場合、これらのスペシャルは一般よりも高いことが保証されているため(つまり、2> 1)、 MAX
を使用できます。 集計関数。これで、基本的に場所とその「推奨パッケージ」の表ができました(つまり、存在する場合は特別、そうでない場合は一般)。これを通常のクエリと予想されるパッケージタイプに結合するだけで、正しい結果が返されます。
免責事項:これらの方法のいずれかの効率についてはよくわかりません。そのため、これを自分でテストすることをお勧めします。
テーブルを再設計するか、効率を上げるために非正規化することを検討している場合は、この設計の方が適していると思います。
GeneralPackages table
id, name
1, General Package 1
SpecialPackages table
id, name
1, Special Package 1
2, Special Package 2
Items table
id, general_package_id, special_package_id, location
1, 1, NULL, America
2, 1, 2, Europe
利点は、データベースレベルでいくつかのルールを適用するのが簡単になることです。
- 場所には常に一般パッケージが必要です(Items.general_package_idはNOT NULLとして定義できます)
- 場所には、一般的なパッケージが1つだけ含まれている必要があります(結合ではなくフィールドに追加すると、指定されたパッケージが1つだけになることが保証されます)
- 場所には、最大で1つの特別なパッケージを含めることができます(結合ではなくフィールドに追加すると、指定されたパッケージが1つだけになることが保証されます)
- Items.general_package_id =GeneralPackages.idの外部キーは、その列に「一般」である有効なパッケージのみが含まれることを保証します。
- special_package_idについても同じことができます。
欠点は、古いクエリの1つを使用するたびに、おそらくUNIONALLを使用する必要があることです。