2

widgetsPostgresには次のテーブルがあります。

ここに画像の説明を入力してください

(そのスクリーンショットは、Excelでの大まかな表現です。)次のような単一のSQLクエリを作成しようとしています。

  1. 今日のwidgets最も早いロード時間でウィジェットを表すレコード。また
  2. 今日ロードされていない場合、widgetsロード時間がこれまでで最も早いもの(テーブル全体)

したがって、上の画像を使用すると、次のようになります。

  • クエリは最初に、今日最初にロードされたウィジェットを返そうとします(そのようなウィジェットが存在する場合)。この場合、今日はIDが3と5003094(それぞれ)のウィジェットのみがロードされました。これら2つのうちwidget_id = 3、他よりも早くロードされたため、これはクエリが返すレコードです。
  • ただし、これら2つのウィジェットがテーブルになく、さらにウィジェットが今日ロードされていないふりをすると、クエリはwidget_id = 12010年にロードされたため、を返します。

クエリでの最初の試みは次のとおりです。

SELECT
    MIN(w.loaded_date_time)
FROM
    widgets w
WHERE
    w.loaded_date_time >= now()
    OR
    1=1

しかし、私はこれが構文的に正しくないことをすぐに知っています。何か案は?前もって感謝します!

4

4 に答える 4

3

1行合計

SELECT *
FROM   widgets
ORDER  BY loaded_date_time < now()::date, loaded_date_time
LIMIT  1;

boolean..式がソートされているため、今日のタイムスタンプ (+ 存在しない未来) を最初に効果的にソートしますFALSE-> TRUE-> NULL.

将来の日付が可能な場合:

ORDER  BY
       (loaded_date_time::date = now()::date) DESC NULLS LAST
      ,loaded_date_time

NULLS LASTloaded_date_timeNULL にできる場合にのみ関連します。これは、最初から許可されていません。この場合、句を削除します。

ウィジェットごとに 1 行

SELECT DISTINCT ON (widget_id)
       widget_id, loaded_date_time
FROM   widgets
ORDER  BY
       widget_id
      ,(loaded_date_time::date = now()::date) DESC
      ,loaded_date_time;

なぜ、どのようにこれが機能するのですか?

  • DISTINCT ON:
  • ORDER BY句では ... ...
    最初widget_idに、明らかに -DISTINCT句と一致する必要があります。
    ... 次に、「今日」のレコードを最初に並べ替えます。何もない場合は、他のレコードが自動的に上に移動します。
    ...最後に、古いレコードが最初にソートされます。

    これにより、目的の行が最初に来て、によって選択されDISTINCTます。すべてが一度に完了します。

  • (loaded_date_time::date = now()::date)式を次のように書き換えると

    (loaded_date_time >= now()::date AND
     loaded_date_time < (now()::date + 1))   -- note: < not: <=
    

.. に単純なインデックスを使用すると、より高速になる可能性がありますloaded_date_time。等号の両側に式がある場合、単純なインデックスをまったく使用できないためです。widget_id (明らかに) にインデックスがあり、おそらく別のインデックスが必要ですloaded_date_time:

CREATE INDEX foo_idx ON widgets (loaded_date_time)

複数列のインデックスは少し速いかもしれません:

CREATE INDEX foo_idx ON widgets (widget_id, loaded_date_time);

EXPLAIN ANLYZE慣れるか、でテスト。そうあるべきです、私はテストしませんでした。そうでない場合は、持っている意味がありません。

于 2012-10-15T18:38:10.507 に答える
1

SQLフィドル

select w.id, w.name, w.loaded_date_time
from (
    select min(loaded_date_time) loaded_date_time
    from widgets
    where loaded_date_time::date = current_date
    union
    select min(loaded_date_time) loaded_date_time
    from widgets
    order by loaded_date_time desc
    limit 1
) s inner join widgets w on w.loaded_date_time = s.loaded_date_time
于 2012-10-15T18:32:20.337 に答える
1

クエリを 2 つのクエリに分割unionし、a を使用しnot exists()てロジックを処理します。

select * from widget
where <primary criteria>
union
select * from widget
where <secondary criteria>
and not exists (
    select * from widget
    where <primary criteria>
)

このようにコーディングすると、特に後でカテゴリを選択する別の方法を追加する場合に、読みやすく、維持しやすくなります。

于 2012-10-15T18:20:16.250 に答える
1

ランキング機能のアプリです。キーは次の順序です。

select w.*
from (select w.*,
             row_number() over (partition by widget_id
                                order by isToday, datetime desc) as seqnum
      from (select w.*,
                   (case when cast(widget_loaded_date_time as date) = cast(now() as date)
                         then 0
                         else 1
                    end) as isToday
            from widgets w
           ) w
     ) w
where seqnum = 1
于 2012-10-15T18:30:36.967 に答える