2016-08-02 17 views
0

IDごとに最新の結果を除いて、すべてのテーブルで「放棄」フラグを設定する必要があります。私はここで動作するクエリがあると思っていましたが、クエリでselectを実行すると不正な結果が出ます - 特定のIDに対して唯一の2つの結果の両方を選択した1つのケースを見ました。私は同じ正確なデータで複数の結果も得ています。 ここで何が間違っていますか?SQL IDごとに最新の結果をすべて選択する

select t.test_row_id, t.test_result_id, t.waived, t.pass, t.comment 
from EV.Test_Result 
join EV.Test_Result as t on EV.Test_Result.test_row_id = t.test_row_id and EV.Test_Result.start_time < t.start_time and t.device_id = 1219 and t.waived = 0 
order by t.test_row_id 

ここで私が実行したい実際のクエリです:

update EV.Test_Result 
set waived = 1 
from EV.Test_Result 
join EV.Test_Result as t on EV.Test_Result.test_row_id = t.test_row_id and EV.Test_Result.start_time < t.start_time and t.device_id = 1219 and t.waived = 0 
+0

一意のタイムスタンプ(少なくとも日時を意味する)を返す日付列がある場合、これはMAX関数では簡単です。しかし、そうでなければ...あなたのテーブル構造にデザイン上の欠陥があるかもしれません。 –

+0

datetime2というstart_time列があります。私もmaxを試しましたが、正しく書かれているのが面倒でした。例がありますか?私はSQLにあまり堪能ではありませんが、これは私の主要な仕事の説明ではありません(私は勉強しようとしていますが!)。 – Johonn

+0

最後の提案は、インデントでクエリをフォーマットすることです。 SQLは文字列に含まれていないインラインスペースを無視します(SQLの文字列区切り文字です)。 –

答えて

1

、あなたは問題を抱えています。

 EV.Test_Result.test_row_id = t.test_row_id 
    and EV.Test_Result.start_time < t.start_time 

このONは、同じIDを持つSTART_TIME値の全てを比較し、START_TIMEがt.start_timeより小さいある結果セットのすべての組み合わせを返します。明らかに、これはあなたが望むものではありません。

    and t.device_id = 1219 
        and t.waived = 0 

これは実際には、述語(ONが技術的に1である)であるが、私はいくつかの理由でsubquery/CTEでこれを使用することを好むだろう:あなたは取得して比較することがありSQL行の数を制限します。

次のようなものは、あなたが必要なものかもしれません:

SELECT A.test_row_id 
    , A.test_result_id 
    , A.waived 
    , A.pass 
    , A.comment 
FROM EV.Test_Result A 
INNER JOIN (SELECT MAX(start_time) AS start_time 
       , test_row_id 
      FROM EV.Test_Result 
      WHERE device_id = 1219 
       AND waived = 0 
      GROUP BY test_row_id 
          ) AS T ON A.test_row_id = T.test_row_id 
            AND A.start_time < T.start_time 
ORDER BY A.test_row_id 

このクエリその後は、あなたが実行していたM:Mクエリとは異なり、ON述語の値の間1:M関係を返します。

UPDATE:あなたが知っているように

、あなたが書いた:私はおずおずとSOに私のクエリを変更しようとしているめちゃくちゃのでは 、私は基本的なSQLクエリ演算子の物理的および論理的な受注を説明することによって、自分自身を買い戻しますよ以下のようなシンプルなSELECT声明:

SELECT <aggregate column>, SUM(<non-aggregate column>) AS Cost 
FROM <table_name> 
WHERE <column> = 'some_value' 
GROUP BY <aggregate column> 
HAVING SUM(<non-aggregate column>) > some_value 
ORDER BY <column> 

あなたは、集計関数を使用する場合、他のすべての列がGROUP BYまたは別の関数に現れなければならないことに注意してください。それは実際に暗記する価値がある、次の順序で論理的にこれを処理しますが、今

は、SQL Serverがそれらの順に書かされることを必要とします、FROM

  • WHERE、GROUP BY、HAVING、SELECT、ORDER BY

ありSELECT - MSDNで見つかった詳細がありますが、これはまた、なぜSELECTオペレータのいずれかの列が集約関数(SUMMINMAXなど)によって、または、グループでなければなりません理由です...と私の怠惰なコードが失敗しましたあなたの最初の試みで。 : ORDER BYは最後に(技術的にはTOP演算子が発生します)、その結果がないと結果が確定しないことに注意してください。DENSE_RANKなどの関数がそれを強制しない限り(SELECTステートメントで発生すると考えられます)。

これは、問題を解決するのに役立ちますが、SQLの仕組みをよりよく理解するのに役立ちます。歓声

+0

oops、そのサブクエリでtest_row_idを指定するのを忘れました。xD –

+0

この非常に有益な答えをありがとう、何が起こっているか少し良く理解するのに役立ちます。 あなたのコードを試してみましたが、サブクエリのWHEREの近くで構文エラーが発生しました。何が間違っているのでしょうか? – Johonn

+0

@Johonn LOL ... xDはい... xD WHERE節が間違っています。 xD私はあなたのクエリーをそれほど変えないように覚えておく必要があります。 xD –

0

あなたは、タイムスタンプの降順でROW_NUMBER()関数順序を試してみて、ROW_NUMBER 1を持つ値をフィルタリングすることができます。ここ

は私のselect文です;クエリ以下

私はフィールドを持つテーブルを使用してOracleでクエリの下にしようとした最新の1

除いIDごとのすべてのレコードを取得する必要があります。id、USER_ID、record_order ADNタイムスタンプを、それが働いた:

select 
      <table_name_alias>.* 
     from 
     (
    select 
    id, 
    user_id, 
     row_number() over (partition by id order by record_order desc) as record_number 
    from 
    <your_table_name> 
) <table_name_alias> 
     where 
    record_number <>1; 

をTeradata DBを使用している場合は、QUALIFYステートメントを試すこともできます。すべてのDBがこれをサポートしているかどうかはわかりません。私はこれを正しく理解していればON述語のカーディナリティが一致するすべての行を返すため

Select 
    table_name.* 
    from table_name 
    QUALIFY row_number() over (partition by id order by record_order desc) <>1; 
+0

答えをありがとう。 "RANK"が新しいテーブル(ランクが予約語に見える)であると仮定すると、私はまだ上記のことをすることができません - 最後の行はエラーです: "期待AS、ID、またはQUOTED_ID"(WHERE )と "無効な列名r"(私はRANKの代わりにrを使用しました) – Johonn

+0

@Johonこのエラーは、派生テーブルにエイリアスが必要なためです。はい、RANKは予約語です。 RowNumまたはRはより良い選択肢です。 –

+0

@Johonn: uは、クエリの下に試すことができ、それは私のために仕事をしたオラクル で 'TABLE1を選択* から(record_order DESCにより、ID順 によって(パーティションを超えるID、USER_ID、ROW_NUMBER()を選択)など。 TABLE_NAMEからのrecord_number)TABLE1 where record_number <> 1; ' Teradata DBを使用している場合は、QUALIFY文を試すこともできます。すべてのDBがこれをサポートしているかどうかはわかりません。 'select * from table_name QUERIFY row_number()over(ID順のパーティション番号 by record_order desc)<> 1;' – Leo

関連する問題