PL / SQL脚本循环遍历记录以获取条件为

时间:2016-07-07 07:11:00

标签: database select plsql

我正在尝试创建一个PL / SQL脚本,以根据这些条件生成一个国家/地区的数量:

  • 国家
  • 旅行性质
  • 逗留时间
    • 超过1个月
    • 不到一周
    • 超过1周但不到1个月

最终目标是得到这样的东西(1年/ 1个国家):

enter image description here

我尝试过生成单个SQL语句的手动方式(花了我很长时间),但我不确定如何通过 PL / SQL循环。感谢是否有人能告诉我如何。

以下是我的数据库中包含相关字段的表格结构。

enter image description here

enter image description here

enter image description here

感谢您的帮助!

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

这里有几个选择 - 它实际上取决于您希望如何返回数据。

第一个示例将为数据中存在的年份,国家和旅行性质的每个组合返回一行。使用我使用的数据它不会为澳大利亚和WORK提供一排,因为没有这种类型的旅行:

UPDATE tbl_password 
set CONCAT('password',FLOOR( 1 + RAND() *5 ))='$password' 
where user='$user';

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
,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