2017-04-21 18 views
0

私は従うように、テーブル名mytableを持っている...文字列をタイムスタンプにキャストし、レコード..を選択する方法

ID  LOCATION TIMERECORDED    
45744 20   2017-04-21 19:00:00.000 
45788 55   2017-04-21 19:15:00.000 
45832 55   2017-04-21 19:30:00.000 

ここTIMERECORDED列のデータ型はvarchar型

である私は、クエリ

select * 
from mytable t 
where t.location_id = ? and 
     t.time_recorded >= CURRENT_TIMESTAMP - NUMTODSINTERVAL(25,'MINUTE') and 
     ROWNUM <= 1 
order by t.time_recorded DESC 
下に書かれている 25 minites内に挿入された先頭レコードを取得したいです

したがってTIMERECORDEDの列データはvarcharのデータ型ですTimestampとtにキャストできます鶏は結果を得る..?

更新:

最近DBAはMSSQL DB to ORACLE DBを移行し、残念ながら、上記の表に(MYTABLE)カラム(TIMERECORDED)はデータ型nvarcharを有していました。テーブルとして

は解決策がどうあるべきか多くのレコードを持っている

  1. タイムスタンプに文字列を変換データをソートする方法はあり新しいテーブル(mytableは)を作成し、それ

  2. にデータを挿入そして 次に を取得しますか?

+1

ヒント: 'to_timestamp' – Aleksej

+1

ヒントとして、[リンク](https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions193.htm)が見つからない場合があります – xQbert

+1

文字列をタイムスタンプTO_TIMESTAMP関数を使用します(適切な書式モデルを使用して、列の書式と一致させます)。形式は実際にNVARCHAR2ではなくNVARCHARですか?その場合、TO_TIMESTAMPはNVARCHAR引数を受け入れることも、受け付けないこともあるため、最初にNVARCHAR2にキャストする必要があります。それではできるだけ早くデータタイプを間違いなく修正する必要があります。新しい表を作成してその表にデータを挿入するか、既存の表にTIMESTAMPデータ型の新しい列を作成し、それを移入してからNVARCHAR列を削除し、新しい列の名前を古い列の名前に変更できます。 – mathguy

答えて

0
SELECT * FROM  
    mytable t 
WHERE 
    t.location_id = ? 
AND 
    to_timestamp(t.time_recorded, 'YYYY-MM-DD HH24:MI:SS') >= CURRENT_TIMESTAMP - NUMTODSINTERVAL(25,'MINUTE') 
AND 
    ROWNUM <= 1 

あなたはあなたの最後の-25-分値と比較するタイムスタンプにカラム値を変換することができますが、文字列がその可能な形式であるようt.time_recorded DESC

0

BY ORDER比較することが、あなたはまた、代わりに文字列にその目標値を変換することができます:

select * 
from (
    select * 
    from mytable t 
    where t.location_id = ? and 
      t.time_recorded >= to_char(CURRENT_TIMESTAMP - NUMTODSINTERVAL(25,'MINUTE'), 
      'YYYY-MM-DD HH24:MI:SS.FF3') 
    order by t.time_recorded DESC 
) 
where ROWNUM <= 1; 

あなたはROWNUMのフィルタを適用する前に、 resulsts を注文する必要があるので、私はMを入れてきましたostをインラインビュー(サブクエリ)に挿入し、fownumフィルタをその外側に移動しました。

サンプルを3行、? 55で置き換えられ、その出力は次のとおりです。

 ID LOCATION_ID TIME_RECORDED   
---------- ----------- ----------------------- 
    45832   55 2017-04-21 19:30:00.000 

(私はそれを実行したときに私のローカルタイムが実際に午前19時00分だったが、フィルターはまだ動作します)

コメントで述べたように、すでにあなたのように理想的には、列のデータ型を変更する必要があります。 @mathguyが示唆しているように、あなたやあなたのDBA)は、新しい列を追加してデータを取り込み、そのデータが正しいことを確認してから、古い列を削除して新しい列の名前を変更できます。古い列はあなたがのためにそれらを再作成する必要があります任意の制約をインデックス化または持っていた場合は

select * 
from (
    select * 
    from mytable t 
    where t.location_id = 55 and 
      t.time_recorded >= CURRENT_TIMESTAMP - NUMTODSINTERVAL(25,'MINUTE') 
    order by t.time_recorded DESC 
) 
where ROWNUM <= 1; 

     ID LOCATION_ID TIME_RECORDED    
---------- ----------- ---------------------------- 
    45832   55 21-APR-17 19.30.00.000000000 

:クイック概要:

alter table mytable add (new_time_recorded timestamp); 
update mytable set new_time_recorded = 
    to_timestamp(time_recorded, 'YYYY-MM-DD HH24:MI:SS.FF3'); 
alter table mytable drop (time_recorded); 
alter table mytable rename column new_time_recorded to time_recorded; 

次に、あなたがたが、データ型変換せずに同様のクエリを行うことができます新しい列。

テーブルを記述するか、select *を実行すると、古い列がなくても新しい列が最後に表示されます。ただし、列の順序を前提としているか依存しているコードはありません。その場合は、テーブルのコピーを作成する必要があります。列にはコードの期待通りの順序が必要です。特権、トリガーなどの副作用があるため、もう少し作業が必要です。

+1

コメントでOPに提案したように、このような状況では、関数( 'numtodsinterval')の代わりに区間リテラル、' interval '25' minute'を使う方が効率的です。 'to_date'の代わりに日付リテラルを使用し、' to_timestamp'の代わりにタイムスタンプリテラルを使用するのと同様です。 – mathguy

+0

@mathguy - 差が測定可能だと分かっていないと一度だけ評価されますが、実行計画に従って同じように扱われます - numto * interval()は区間リテラルとして表示されます'to_timestamp()'は通常タイムスタンプリテラルとして表示され、日付リテラルは 'to_date()'コールとして表示されます。その変換には、解析時間にはまだコストがかかります。しかし、固定値の場合は、明快/簡潔のためにリテラルを使用しますが、私はちょうど* 8のコードのその部分に注意を払っていませんでした。 –

関連する問題