LoginSignup
2
1

More than 3 years have passed since last update.

複数ANDにORを追加する時の評価順序に注意する

Last updated at Posted at 2019-04-30

軽い修正かと思ってDELETEやUPDATEで気づかないと結構あわわなので注意

背景

WHEREに対する3つのAND条件にOR条件を追加する必要があった。
具体的にはNULLを条件に含める必要があり、比較演算子では対象から抜け落ちてしまうため条件を追加した。

結論

間のANDにOR条件を追加したい場合、評価のされ方が変わるので()で囲む必要がある

# 現行
A AND B AND C

# 追加
## 誤
A AND B OR X AND C
-> (A AND B) OR (C AND D) 

## 正
A AND (B OR X) AND C

定期格納実施後に不正データを削除するSQL

格納したばかりのデータと同じデータが過去のデータに合った場合に削除する

DELETE FROM ${data_warehouse.database.table}
WHERE
  /* 定期格納したデータの対象期間 */
  TD_TIME_RANGE(time, TD_TIME_PARSE('${date_since}', '${date_timezone}'), TD_TIME_ADD(TD_TIME_PARSE('${date_until}', '${date_timezone}'), '1s'))
AND
  /* 過去に格納されているデータ */
  (updated_at < ${import_time} OR updated_at IS NULL) /* <-- ここにNULLを()なしで入れた */
AND
  /* データを一意とする条件(スキーマの構造的にPKがないので) */
  ARRAY_JOIN(ARRAY[${primary_keys}], ',')
IN (
  /* 格納したばかりのデータ */
  SELECT
    ARRAY_JOIN(ARRAY[${primary_keys}], ',')
  FROM
    ${data_warehouse.database.table}
  WHERE
    TD_TIME_RANGE(time, TD_TIME_PARSE('${since_date}', '${timezone}'), TD_TIME_ADD(TD_TIME_PARSE('${until_date}', '${timezone}'), '1s'))
  AND
    updated_at = ${import_time}
  )

直前に格納したデータの対象期間
かつ
過去に格納されているデータまたはNULL
かつ
格納したばかりのデータと同じ

という条件のデータだけを削除するはずが、

直前に格納したデータの対象期間
かつ
過去に格納されているデータ
を全部削除するという形になってしまった。

つまり格納したデータ全部削除していた。(何も格納していないことになっていた。)

雑感

シンプルな対応でも少し複雑な処理に対して行う場合は、周辺の再確認時間を適切に確保して安直に行わないようにする

一意じゃないデータが入り得るのに一意のデータを入れていけないとなると大変

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1