質問

SQL ステートメントで DATEDIFF を使用しています。それを選択していますが、WHERE 句でも使用する必要があります。このステートメントは機能しません...

SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
WHERE InitialSave <= 10

次のようなメッセージが表示されます。 無効な列名「InitialSave」

しかし、このステートメントはうまく機能します...

SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
WHERE DATEDIFF(ss, BegTime, EndTime) <= 10

私の中のプログラマーは、これは非効率的である (関数を 2 回呼び出しているようだ) と言っています。

そこで質問が 2 つあります。最初のステートメントが機能しないのはなぜですか?2 番目のステートメントを使用して実行するのは非効率ですか?

役に立ちましたか?

解決

彼らはどこが実行されるまで生成されていないので、

あなたは、どこ文でselect文で定義された列にアクセスすることはできません。

あなたはしかし、これを行うことができます。

select InitialSave from 
(SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable) aTable
WHERE InitialSave <= 10

追記として - これは、本質的にそれが最初に定義されていますどこの面でどこステートメントにDATEDIFFを移動します。あなたが使用するんだがあれば、文はインデックスがのように効率的に使用されないように、可能であれば避けるべき原因となる場所の列に関数を使用するDateDiff関数その後、あなたはそれを行うようになってきました!

他のヒント

注記: 最初にこの回答を書いたとき、列の 1 つにインデックスを付けると、他の回答よりもパフォーマンスの高いクエリを作成できると言いました (そして Dan Fuller のことにも言及しました)。しかし、私は100%正しく考えていたわけではありませんでした。実際のところ、計算列またはインデックス付き (マテリアライズド) ビューがなければ、テーブル全体のスキャンは次のようになります。 必須, 、比較される 2 つの日付列は、 同じ テーブル!

私は、以下の情報にはまだ価値があると信じています。つまり、1) 異なるテーブルの列間の比較など、適切な状況でパフォーマンスが向上する可能性、2) SQL 開発者がベスト プラクティスに従い、再構築する習慣を促進することです。彼らの考えは正しい方向に向かっています。

条件を Sargable にする

私が言及しているベスト プラクティスは、次のように、1 つの列を比較演算子の片側に単独で移動することです。

SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM dbo.MyTable T
WHERE T.EndTime <= T.BegTime + '00:00:10'

前述したように、これによって単一テーブルのスキャンが回避されるわけではありませんが、次のような状況では大きな違いが生じる可能性があります。

SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM
   dbo.BeginTime B
   INNER JOIN dbo.EndTime E
      ON B.BeginTime <= E.EndTime
      AND B.BeginTime + '00:00:10' > E.EndTime

EndTime 両方の条件にあり、比較の片側に単独で存在します。と仮定すると、 BeginTime テーブルの行数ははるかに少なく、 EndTime テーブルの列にインデックスがあります EndTime, 、これは、他のものを使用するよりもはるかに優れたパフォーマンスを発揮します。 DateDiff(second, B.BeginTime, E.EndTime). 。それは今です 検索可能な, これは、有効な「検索引数」があることを意味します。つまり、エンジンとして スキャンBeginTime テーブル、それはできます 求めるEndTime テーブル。どの列を演算子の片側に単独で配置するかを慎重に選択する必要があります。次のようにして実験してみる価値があります。 BeginTime 代数を実行して、それ自体で切り替えます AND B.BeginTime > E.EndTime - '00:00:10'

DateDiff の精度

それも指摘しておきたいと思います DateDiff 戻らない 経過 時間ではなく、回数を数えます。 境界線 交差した。に電話した場合 DateDiff 秒の戻り値を使用する 1, 、これは意味するかもしれません 3 ms 経過時間、あるいはそれが意味するもの 1997 ms!これは基本的に +-1 時間単位の精度です。+- 1/2 時間単位の精度を高めるには、以下のクエリを比較する必要があります。 0EndTime - BegTime:

SELECT DateDiff(second, 0, EndTime - BegTime) AS InitialSave
FROM MyTable
WHERE EndTime <= BegTime + '00:00:10'

これにより、最大丸め誤差は合計 2 秒ではなく、わずか 1 秒になります (実際には、floor() 操作)。減算のみができることに注意してください。 datetime データ型 -- 減算する date または time 変換する必要がある値 datetime または、他の方法を使用してより良い精度を取得します( DateAdd, DateDiff おそらく他のジャンク、またはおそらくより高精度の時間単位を使用して除算する可能性があります)。

この原則は、時間、日、月などの大きな単位を数える場合に特に重要です。あ DateDiff1 month 62 日離れている可能性があります (2013 年 7 月 1 日から 2013 年 8 月 31 日を考えてください)。

「機能」させるだけでなく、インデックスを使用する必要があります

インデックス付きの計算列、またはインデックス付きのビューを使用します。それ以外の場合は、テーブル スキャンが行われます。十分な行数が得られると、 痛み 遅いスキャンのせいで!

計算列とインデックス:

ALTER TABLE MyTable ADD
    ComputedDate  AS DATEDIFF(ss,BegTime, EndTime)
GO
CREATE NONCLUSTERED INDEX IX_MyTable_ComputedDate  ON MyTable 
    (
    ComputedDate
    ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

ビューとインデックスを作成します。

CREATE VIEW YourNewView
AS
SELECT
    KeyValues
        ,DATEDIFF(ss, BegTime, EndTime) AS InitialSave
    FROM MyTable
GO
CREATE CLUSTERED INDEX IX_YourNewView
    ON YourNewView(InitialSave)
GO

あなたが代わりに列の別名の機能を使用する必要があります - それは、COUNT(*)などと同じであるPITA

の代替として、あなたは計算カラムを使用することができます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top