6

私は2つのテーブルを持っています:

CREATE TABLE plans
    (id int, benefit varchar(5), clip_state int);

INSERT INTO plans
    (id, benefit, clip_state)
VALUES
    (1, 'A', 1),
    (2, 'A', 0),
    (3, 'B', 0),
    (4, 'C', 0);

CREATE TABLE clip_states
    (state varchar(2), clip_state int);

INSERT INTO clip_states
    (state, clip_state)
VALUES
    ('LA', 1),
    ('FL', 0);

clip_stateは 0 または 1 のいずれかであり、データ モデルでは2 つの情報からテーブル内のプランを1 つまたは 1 つも照会できないことに注意してください: & 。まず、条件を使用して、テーブルを最大 2 行 (1 行は= 0、もう 1 行は = 1) にフィルター処理できます。次に、使用してテーブルと結合することにより、次のチェックにより結果を 1 行 (またはゼロ) に減らすことができます。plansbenefitstatebenefitplansclip_statestateclip_states

  • stateがテーブルにある場合は、が 2 つのテーブル間で一致しclip_statesていることを確認してください。clip_state一致しない場合、結果は返されません。
  • stateにが存在しない場合は、= 0を持つテーブルclip_states内の行とのみ一致します。plansclip_state

トリックを行う私のクエリは次のとおりです。

SELECT id, p.clip_state, benefit
FROM plans p
LEFT JOIN clip_states cs ON STATE IN ('LA')
WHERE benefit = 'A' AND
(p.clip_state = cs.clip_state OR (p.clip_state = 0 AND cs.clip_state IS NULL));

ご覧のとおり、左結合は 2 つのテーブル間の関係で結合されないため、非常に奇妙です。だから、私の質問は:

  • このような結合があるのは普通ですか?
  • より良い解決策 (クリーン & パフォーマンス) はありますか?

私のソリューションはhttp://sqlfiddle.com/#!1/8912d/53で確認できます。

更新 1: 上記の質問のテキストを更新しました。

更新 2: 詳細情報

  1. aがテーブルにstateない場合、暗黙的に 0 に等しくなります。それ以外の場合は、テーブル内にあります。clip_statesclip_stateclip_state
  2. 与えられた 2 つの info:benefitとから、与えられた の=である表stateの行を見つけます。もちろん、一致しない場合、行は返されません。plansplans.clip_stateclip_statestate
4

5 に答える 5

1

更新された質問に対する更新された回答:

SELECT p.*
FROM   plans p
WHERE  p.benefit = 'A'
AND    NOT  EXISTS (
  SELECT 1
  FROM   clip_states cs
  WHERE  cs.state = 'LA'
  AND    cs.clip_state <> p.clip_state
  )
ORDER  BY p.clip_state
LIMIT  1;

->sqlfiddle

それは定義である可能性があります:

  1. plans指定された のtable 内のすべての行を検索しますbenefit

  2. 指定された のclip_stateテーブル内の同じ列に一致しない行を削除します。clip_statesstate

  3. 残りの行から、 の値が最も低い行を返しますclip_state

また、

clip_state0 または 1 のいずれか

booleanの代わりにデータ型を使用する必要がありますint

于 2013-01-29T12:39:43.673 に答える
1

完全に異なるアプローチ:

  1. その状態がまだテーブルにない場合は、必要な状態を 0 でclip_statesテーブルに「追加」します。clip_state

  2. plans結果セットをonに内部結合しclip_state、さらに on でフィルタリングしstateます。

これは次のようになります。

SELECT p.*
FROM plans p
INNER JOIN (
  SELECT state, clip_state FROM clip_states
  UNION ALL
  (
  SELECT 'LA', 0
  EXCEPT
  SELECT state, 0 FROM clip_states
  )
) cs
ON p.clip_state = cs.clip_state
WHERE p.benefit = 'A'
  AND cs.state = 'LA'
;

「実行中」のこのクエリは次のとおりです。http://sqlfiddle.com/#!1/b0feb/7

私が何かを見逃していない限り、あなたの要件と一致しているようです。

于 2013-01-29T19:37:18.200 に答える
0

確かに、LEFT JOINここでは奇妙に見えます。

  1. plansclip_statesテーブルの間に結合条件がありません。
  2. SELECTリストの列を使用しないため、目的の値をclip_state取得できません。NULL

次の方法で実行することをお勧めします(SQL-Fiddleでも)。

SELECT id, p.benefit, coalesce(cs.clip_state, 0) clip_state
FROM plans p
LEFT JOIN clip_states cs ON cs.clip_state=p.clip_state AND cs.state IN ('LA')
WHERE p.benefit = 'A';
  1. 結合条件をクエリWHEREFROM一部に移動し、簡略化しました。
  2. テーブルの列をclip_statesSELECTリストに追加しましたNULL。一致する行がない場合に備えて、列を追加しました。
  3. cs.clip_stateの場合NULL、予想通り0に変換します。

私はこれがあなたが必要とすることをするだろうと思います。

結合のこの視覚的な説明を見てください、私はそれが非常に役立つと思います。

于 2013-01-29T08:11:49.193 に答える
0

解決策として次のクエリを使用する必要があると思います。クエリプランを確認したところ、質問のクエリよりも一歩優れていることがわかりました。アイデアは、最初に計画を絞り込んでから、clip_states テーブルと結合することです。

SELECT *
FROM (
    SELECT DISTINCT id, clip_state, benefit
    FROM plans
    WHERE benefit = 'A') p
LEFT JOIN clip_states cs ON state IN ('LA')
WHERE (p.clip_state = cs.clip_state OR (p.clip_state = 0 AND cs.clip_state IS NULL));

皆さんありがとう。

于 2013-01-30T20:40:48.203 に答える
0

それがトリックを行うことを考えると:

  • このような結合があるのは普通ですか?

それは通常行われている方法ではありません。しかし、私の見方では、JOIN は ON の後に任意の条件を取るだけです。

  • より良い解決策 (クリーン & パフォーマンス) はありますか?

ここで利用可能な最短のソリューションのように見えますが、パフォーマンスが低下する理由がわかりません。

このクエリから VIEW を作成し、選択したフィールドに STATE フィールドを含めると、このビューから次のようにクエリを作成できます。

SELECT * FROM stateview WHERE state='FL'

ちなみに、偶然にも、vyegorov によって提供されたソリューションは、私がいくつかのテストを行うために sql-fiddle に入力したものとまったく同じです。しかし、それは正しくないと判断したため、その後削除しました。

于 2013-01-29T10:03:18.053 に答える