2015-11-10 133 views
1

我有3個表,用戶,旅行和tripDetails。複雜SQL查詢與樞軸

id(INT), user_id(INT) & dateCreated(DATE) 

和4行中的tripDetails表中創建:

id(INT), trip_id(INT), field(VARCHAR) & value(VARCHAR) 

其中字段是'SMARTBOX當用戶創建一個跳閘在行程表中創建具有以下字段的行.destination」, 'smartbox.dateFrom', 'smartbox.dateTo', 'smartbox.numberOfPeople' 和值列是一個varchar。 但是,假設用戶更改了目的地並保存了此更改,在旅行表中創建了一條新記錄,並且在tripDetails表(更新的目的地)中創建了一條記錄

現在我想要創建一個選擇這會給我一個用戶的行程的快照對於一個給定的一天,列標題:

user_id, trip_id, destination, dateFrom, dateTo, numberOfPeople, givenDay(DATE) 

例如,如果一個領域已經對給定的一天改變了,所有的其他列會顯示什麼他們最近的值是相對於那一天。

我已經成立了一個sqlfiddle here

+0

在tripDetails中,您是否有任何時間戳列?還有什麼是'givenDay'? – Utsav

+0

不,創建記錄的日期存儲在旅行表中。 givenDay是我要拍攝快照的那一天 – BrotherBarnabas

+0

您的'tripDetails.value'列值允許包含NULL嗎? – nop77svk

回答

1

首先,請允許我說:你只能用「壓倒一切的鍵/值對」處理數據的方式有些有嚴重缺陷的數據模型。

現在爲您的問題的解決方案。假設

  • tripDetails.value列聲明not null
  • 你的SQL客戶端會詢問您的givenDate值,
  • 您提供您指定日期的查詢中(精確)格式yyyy-mm-dd

您的查詢可能看起來像

with pivot$ as (
    select 
     U.id as user_id, T.id as trip_id, max(T.dateCreated) as trip_date, 
     max(decode(TD.field, 'smartbox.destination', TD.value)) as trip_destination, 
     max(decode(TD.field, 'smartbox.dateFrom', TD.value)) as trip_date_from, 
     max(decode(TD.field, 'smartbox.dateTo', TD.value)) as trip_date_to, 
     max(decode(TD.field, 'smartbox.numberOfPeople', TD.value)) as trip_no_of_people 
    from users U 
     join trips T 
      on T.user_id = U.id 
     join tripDetails TD 
      on TD.trip_id = T.id 
      and TD.field in ('smartbox.destination', 'smartbox.dateFrom', 'smartbox.dateTo', 'smartbox.numberOfPeople') 
    where T.dateCreated <= date'&givenDate' 
    group by U.id, T.id 
), 
resolve_versioning$ as (
    select user_id, trip_id, trip_date, 
     first_value(trip_destination) ignore nulls over (partition by user_id order by trip_date desc rows between current row and unbounded following) as trip_destination, 
     first_value(trip_date_from) ignore nulls over (partition by user_id order by trip_date desc rows between current row and unbounded following) as trip_date_from, 
     first_value(trip_date_to) ignore nulls over (partition by user_id order by trip_date desc rows between current row and unbounded following) as trip_date_to, 
     first_value(trip_no_of_people) ignore nulls over (partition by user_id order by trip_date desc rows between current row and unbounded following) as trip_no_of_people, 
     row_number() over (partition by user_id order by trip_date desc) as relevance$ 
    from pivot$ 
) 
select user_id, trip_id, 
    trip_destination, trip_date_from, trip_date_to, trip_no_of_people, 
    date'&givenDate' as given_date 
from resolve_versioning$ 
where relevance$ <= 1 
; 

這三個步驟,做:

  • pivot$子查詢denormalizes您的鍵/值對更廣泛的行,與trip_id作爲數據集的邏輯主鍵,有效地離開列NULL時沒有鍵/值對那trip_id。 (順便提一句,這是tripDetails.value列的非空性對查詢成功至關重要的地方)
  • resolve_versioning$子查詢利用first_value()分析函數,處理用戶的所有行程的每個單獨行程詳細信息(partition by user_id),找到相應旅程細節的第一個(first_value)非空值(ignore nulls),從「最年輕」的旅行日期返回到較長的日期(order by trip_date desc)...或者,如果您以其他方式查看在旅行日期的順序中查找行程細節的最後一個非空值。
  • rows between current row and unbounded following是一種「神奇」,正確處理窗口爲特定分析order by所必需的。 (Read here for an explanation.
  • 整個row_number() over (partition by user_id order by trip_date desc)只是將所有從1開始的結果行向上編號,其中1被分配給行程日期排序中的「最年輕」行。然後,在最外面的選擇中,整個結果被過濾以僅顯示最年輕的行(relevance$ <= 1)。

享受!

+0

無法運行此操作,也不能確定錯誤的位置是「ORA-00907:缺少右括號」。 SQL小提琴在這裏:http://sqlfiddle.com/#!4/10e04/3 – BrotherBarnabas

+0

感謝SQLfiddle。答案已更新。 – nop77svk