2016-07-07 422 views
0

我想創建一個PL/SQL腳本基於這些條件的國家產生的數量:PL/SQL腳本,通過記錄循環得到的所有記錄與條件

  • 國家
  • 自然旅行
  • 入住天數
    • 1個多月
    • 減超過1周
    • 1周以上,但不到1個月

的最終目標是讓這樣的事情(1年/ 1國):

enter image description here

我試圖通過手動方式(需要很長時間)生成單個SQL語句,但我不確定如何通過PL/SQL循環執行此操作。欣賞是否有人能告訴我如何。

下面是我的數據庫中的相關字段的表結構。

enter image description here

enter image description here

enter image description here

感謝您的幫助!

+0

你能提供一些示例數據(FE在pastebin.com)像腳本來創建數據庫有一些數據?它可以在沒有PL/SQL的情況下完成,並且不需要太多時間。 –

回答

0

SQL

select c.country_name as country, 
     a.nature_of_travel, 
     case d.rn 
     when 1 then 'More than 1 month' 
     when 2 then 'Less than 1 week' 
     else 'Between 1 week and 1 month' 
     end length_of_stay, 
     count(*) number_of_trips, 
     to_char(b.from_date,'YYYY') year 
    from TB_TRAVELITINERARY b 
    join TB_TRIP a on a.trip_id=b.trip_id 
    join TB_COUNTRY c on b.country_code= c.country_code 
    join (select rownum rn from dual connect by level < 4) d on 
    case when add_months(b.from_date,1) < b.to_date then 1 
      when b.from_date+7 > b.to_date then 2 
      else 3 
    end = d.rn 
group by c.country_name, 
     a.nature_of_travel, 
     case d.rn 
     when 1 then 'More than 1 month' 
     when 2 then 'Less than 1 week' 
     else 'Between 1 week and 1 month' 
     end, 
     to_char(b.from_date,'YYYY')   

PL/SQL

DECLARE 
    TYPE array_t IS VARRAY (3) OF VARCHAR2 (30); 
    notarr array_t := array_t ('More than 1 month', 'Less than 1 week','Between 1 week and 1 month'); 
BEGIN 
    FOR c1 IN ( SELECT country_name, nature_of_travel, 
         CASE WHEN ADD_MONTHS (from_date, 1) < TO_DATE THEN 1 
          WHEN from_date + 7 > TO_DATE THEN 2 
          ELSE 3 
         END los, 
         to_char (from_date,'YYYY') yr, 
         COUNT (*) cnt 
        FROM tb_travelitinerary a 
        JOIN tb_trip b ON a.trip_id = b.trip_id 
        JOIN tb_country c ON a.country_code = c.country_code 
       GROUP BY country_name, nature_of_travel, CASE WHEN ADD_MONTHS (from_date, 1) > TO_DATE THEN 1 WHEN from_date + 7 < TO_DATE THEN 2 ELSE 3 END, to_char (from_date,'YYYY') 
       ORDER BY 4, 1, 2, 3) 
    LOOP 
    DBMS_OUTPUT.PUT_LINE(rpad(c1.COUNTRY_NAME,30)||' '||rpad(c1.NATURE_OF_TRAVEL,8)||' '||rpad(notarr(c1.LOS),27) 
          ||' '||to_char(c1.cnt,'999999990')||' '||c1.yr); 
    END LOOP; 
END; 

示例輸出:

SQL

enter image description here

PL/SQL

enter image description here

+0

謝謝Mottor ..我太如此如此抱歉..我不小心在我的表列上發生了錯誤。TB_TRAVEL_ITINERARY應該有列TRIP_ID而不是其他方式..這就是爲什麼不管我如何嘗試我們的代碼它不工作。真的很感謝你的幫助,雖然..我已經更新了表格。 = X – user3188291

+0

我改變了它 – Mottor

+0

您好mottor,當您運行ur腳本時能夠提供我的示例輸出嗎?我從運行你的第一個腳本得到的輸出只是一個國家名稱列表。 :( – user3188291

0

這裏有幾個選擇 - 它取決於您希望如何返回數據。

第一個示例將針對數據中存在的每個旅行年份,國家和性質組合返回一行。隨着數據我已經用它不會給澳大利亞一個行和工作,因爲沒有這種類型的車次:

WITH 
tb_country AS 
    (SELECT 'ABW' country_code, 'Aruba' country_name FROM dual UNION ALL 
    SELECT 'AFG', 'Afghanistan' FROM dual UNION ALL 
    SELECT 'AGO', 'Angola' FROM dual UNION ALL 
    SELECT 'AUS', 'Australia' FROM dual 
) 
,tb_travleItinerary AS 
    (SELECT 1 itinerary_id, 1 trip_id, 'AUS' country_code, TO_DATE('19/05/2016','DD/MM/YYYY') date_from, TO_DATE('30/05/2016','DD/MM/YYYY') date_to FROM dual UNION ALL 
    SELECT 2, 3, 'AFG', TO_DATE('10/01/2016','DD/MM/YYYY'), TO_DATE('13/01/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 3, 2, 'AFG', TO_DATE('10/02/2016','DD/MM/YYYY'), TO_DATE('01/06/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 4, 5, 'AFG', TO_DATE('10/03/2016','DD/MM/YYYY'), TO_DATE('13/03/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 5, 7, 'AFG', TO_DATE('01/01/2016','DD/MM/YYYY'), TO_DATE('03/01/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 6, 4, 'AFG', TO_DATE('01/10/2016','DD/MM/YYYY'), TO_DATE('29/10/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 7, 6, 'AFG', TO_DATE('12/01/2016','DD/MM/YYYY'), TO_DATE('11/05/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 8, 8, 'AFG', TO_DATE('15/01/2016','DD/MM/YYYY'), TO_DATE('18/01/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 9, 9, 'AFG', TO_DATE('22/01/2016','DD/MM/YYYY'), TO_DATE('13/01/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 10, 10, 'AFG', TO_DATE('31/01/2016','DD/MM/YYYY'), TO_DATE('18/02/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 11, 11, 'AFG', TO_DATE('02/02/2016','DD/MM/YYYY'), TO_DATE('13/10/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 12, 12, 'AFG', TO_DATE('10/02/2016','DD/MM/YYYY'), TO_DATE('11/02/2016','DD/MM/YYYY') FROM dual 
) 
,tb_trip AS 
    (SELECT 1 trip_id, 'HOLIDAY' nature_of_travel FROM dual UNION ALL 
    SELECT 2, 'STUDY' FROM dual UNION ALL 
    SELECT 3, 'WORK' FROM dual UNION ALL 
    SELECT 4, 'HOLIDAY' FROM dual UNION ALL 
    SELECT 5, 'STUDY' FROM dual UNION ALL 
    SELECT 6, 'WORK' FROM dual UNION ALL 
    SELECT 7, 'HOLIDAY' FROM dual UNION ALL 
    SELECT 8, 'STUDY' FROM dual UNION ALL 
    SELECT 9, 'WORK' FROM dual UNION ALL 
    SELECT 10, 'HOLIDAY' FROM dual UNION ALL 
    SELECT 11, 'STUDY' FROM dual UNION ALL 
    SELECT 12, 'WORK' FROM dual 
) 
SELECT 
country_name 
,nature_of_travel 
--,length_of_stay 
,year 
,SUM(less_than_one_week)   count_less_than_one_week 
,SUM(more_than_one_month)  count_more_than_one_month 
,SUM(other_duration)    count_other_duration 
FROM 
(SELECT 
    c.country_name 
    ,t.nature_of_travel 
    ,CASE 
    WHEN ti.date_to - ti.date_from < 7 
    THEN 'Less than 1 week' 
    WHEN ti.date_to - ti.date_from > 30 --note : you need to dfine what you mean by a month 
    THEN 'More than 1 month' 
    ELSE 'Between 1 week and 1 month' 
    END         length_of_stay 
    ,CASE 
    WHEN ti.date_to - ti.date_from < 7 
    THEN 1 
    ELSE 0 
    END         less_than_one_week 
    ,CASE 
    WHEN ti.date_to - ti.date_from > 30 
    THEN 1 
    ELSE 0 
    END         more_than_one_month 
    ,CASE 
    WHEN ti.date_to - ti.date_from BETWEEN 7 AND 30 
    THEN 1 
    ELSE 0 
    END         other_duration 
    ,TO_CHAR(ti.date_from,'YYYY')   year 
    FROM 
    tb_country     c 
    ,tb_travleItinerary   ti 
    ,tb_trip      t 
    WHERE 1=1 
    AND c.country_code = ti.country_code 
    AND ti.trip_id = t.trip_id 
) raw_data 
WHERE 1=1 
GROUP BY 
country_name 
,nature_of_travel 
,year 
ORDER BY 
country_name 
,nature_of_travel 
,year 
; 

enter image description here

第二個例子將返回一行對一年中的每組合數據中存在的國家/地區。對於每一行,你會得到所有旅行類型和持續時間的計數,即使計數爲零:

WITH 
tb_country AS 
    (SELECT 'ABW' country_code, 'Aruba' country_name FROM dual UNION ALL 
    SELECT 'AFG', 'Afghanistan' FROM dual UNION ALL 
    SELECT 'AGO', 'Angola' FROM dual UNION ALL 
    SELECT 'AUS', 'Australia' FROM dual 
) 
,tb_travleItinerary AS 
    (SELECT 1 itinerary_id, 1 trip_id, 'AUS' country_code, TO_DATE('19/05/2016','DD/MM/YYYY') date_from, TO_DATE('30/05/2016','DD/MM/YYYY') date_to FROM dual UNION ALL 
    SELECT 2, 3, 'AFG', TO_DATE('10/01/2016','DD/MM/YYYY'), TO_DATE('13/01/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 3, 2, 'AFG', TO_DATE('10/02/2016','DD/MM/YYYY'), TO_DATE('01/06/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 4, 5, 'AFG', TO_DATE('10/03/2016','DD/MM/YYYY'), TO_DATE('13/03/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 5, 7, 'AFG', TO_DATE('01/01/2016','DD/MM/YYYY'), TO_DATE('03/01/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 6, 4, 'AFG', TO_DATE('01/10/2016','DD/MM/YYYY'), TO_DATE('29/10/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 7, 6, 'AFG', TO_DATE('12/01/2016','DD/MM/YYYY'), TO_DATE('11/05/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 8, 8, 'AFG', TO_DATE('15/01/2016','DD/MM/YYYY'), TO_DATE('18/01/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 9, 9, 'AFG', TO_DATE('22/01/2016','DD/MM/YYYY'), TO_DATE('13/01/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 10, 10, 'AFG', TO_DATE('31/01/2016','DD/MM/YYYY'), TO_DATE('18/02/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 11, 11, 'AFG', TO_DATE('02/02/2016','DD/MM/YYYY'), TO_DATE('13/10/2016','DD/MM/YYYY') FROM dual UNION ALL 
    SELECT 12, 12, 'AFG', TO_DATE('10/02/2016','DD/MM/YYYY'), TO_DATE('11/02/2016','DD/MM/YYYY') FROM dual 
) 
,tb_trip AS 
    (SELECT 1 trip_id, 'HOLIDAY' nature_of_travel FROM dual UNION ALL 
    SELECT 2, 'STUDY' FROM dual UNION ALL 
    SELECT 3, 'WORK' FROM dual UNION ALL 
    SELECT 4, 'HOLIDAY' FROM dual UNION ALL 
    SELECT 5, 'STUDY' FROM dual UNION ALL 
    SELECT 6, 'WORK' FROM dual UNION ALL 
    SELECT 7, 'HOLIDAY' FROM dual UNION ALL 
    SELECT 8, 'STUDY' FROM dual UNION ALL 
    SELECT 9, 'WORK' FROM dual UNION ALL 
    SELECT 10, 'HOLIDAY' FROM dual UNION ALL 
    SELECT 11, 'STUDY' FROM dual UNION ALL 
    SELECT 12, 'WORK' FROM dual 
) 
SELECT 
country_name 
,year 
,(SELECT count(*) 
    FROM tb_travleItinerary ti2, tb_trip tt 
    WHERE ti2.country_code = raw_data.country_code 
    AND TO_CHAR(ti2.date_from,'YYYY') = raw_data.year 
    AND ti2.trip_id = tt.trip_id 
    AND tt.nature_of_travel = 'HOLIDAY' 
    AND ti2.date_to - ti2.date_from < 7 
)            holiday_lt_1_week 
,(SELECT count(*) 
    FROM tb_travleItinerary ti2, tb_trip tt 
    WHERE ti2.country_code = raw_data.country_code 
    AND TO_CHAR(ti2.date_from,'YYYY') = raw_data.year 
    AND ti2.trip_id = tt.trip_id 
    AND tt.nature_of_travel = 'HOLIDAY' 
    AND ti2.date_to - ti2.date_from > 30 
)            holiday_gt_1_month 
,(SELECT count(*) 
    FROM tb_travleItinerary ti2, tb_trip tt 
    WHERE ti2.country_code = raw_data.country_code 
    AND TO_CHAR(ti2.date_from,'YYYY') = raw_data.year 
    AND ti2.trip_id = tt.trip_id 
    AND tt.nature_of_travel = 'HOLIDAY' 
    AND ti2.date_to - ti2.date_from BETWEEN 7 AND 30 
)            holiday_other 
,(SELECT count(*) 
    FROM tb_travleItinerary ti2, tb_trip tt 
    WHERE ti2.country_code = raw_data.country_code 
    AND TO_CHAR(ti2.date_from,'YYYY') = raw_data.year 
    AND ti2.trip_id = tt.trip_id 
    AND tt.nature_of_travel = 'WORK' 
    AND ti2.date_to - ti2.date_from < 7 
)            work_lt_1_week 
,(SELECT count(*) 
    FROM tb_travleItinerary ti2, tb_trip tt 
    WHERE ti2.country_code = raw_data.country_code 
    AND TO_CHAR(ti2.date_from,'YYYY') = raw_data.year 
    AND ti2.trip_id = tt.trip_id 
    AND tt.nature_of_travel = 'WORK' 
    AND ti2.date_to - ti2.date_from > 30 
)            work_gt_1_month 
,(SELECT count(*) 
    FROM tb_travleItinerary ti2, tb_trip tt 
    WHERE ti2.country_code = raw_data.country_code 
    AND TO_CHAR(ti2.date_from,'YYYY') = raw_data.year 
    AND ti2.trip_id = tt.trip_id 
    AND tt.nature_of_travel = 'WORK' 
    AND ti2.date_to - ti2.date_from BETWEEN 7 AND 30 
)            work_other 
,(SELECT count(*) 
    FROM tb_travleItinerary ti2, tb_trip tt 
    WHERE ti2.country_code = raw_data.country_code 
    AND TO_CHAR(ti2.date_from,'YYYY') = raw_data.year 
    AND ti2.trip_id = tt.trip_id 
    AND tt.nature_of_travel = 'STUDY' 
    AND ti2.date_to - ti2.date_from < 7 
)            study_lt_1_week 
,(SELECT count(*) 
    FROM tb_travleItinerary ti2, tb_trip tt 
    WHERE ti2.country_code = raw_data.country_code 
    AND TO_CHAR(ti2.date_from,'YYYY') = raw_data.year 
    AND ti2.trip_id = tt.trip_id 
    AND tt.nature_of_travel = 'STUDY' 
    AND ti2.date_to - ti2.date_from > 30 
)            study_gt_1_month 
,(SELECT count(*) 
    FROM tb_travleItinerary ti2, tb_trip tt 
    WHERE ti2.country_code = raw_data.country_code 
    AND TO_CHAR(ti2.date_from,'YYYY') = raw_data.year 
    AND ti2.trip_id = tt.trip_id 
    AND tt.nature_of_travel = 'STUDY' 
    AND ti2.date_to - ti2.date_from BETWEEN 7 AND 30 
)            study_other 
FROM 
(SELECT DISTINCT 
    c.country_name 
    ,c.country_code 
    ,TO_CHAR(ti.date_from,'YYYY')   year 
    FROM 
    tb_country     c 
    ,tb_travleItinerary   ti 
    WHERE 1=1 
    AND c.country_code = ti.country_code 
) raw_data 
WHERE 1=1 

enter image description here