pradeep kumar Ответов: 2

Значения переменных в предложении oracle where


I am trying to pass an variable value in my Select statement where clause


DATE_DIM table is like below

UNIQUE_ID   WEEK_NAME   WEEK_BEGIN  WEEK_END
1   Week 6, 2018    20180205    20180211
2   Week 5, 2018    20180129    20180204
3   Week 4, 2018    20180122    20180128
4   Week 3, 2018    20180115    20180121


And Fact Table is like

ACCT_ID WEEK_NAME   SALES
10001   20180205    10
10001   20180206    20
10001   20180207    10
10001   20180208    15
1002    20180129    100
1002    20180130    100
1002    20180131    100
1002    20180132    100


Here I need an Output like

ACCT_ID WEEK_NAME   SALES
10001   Week 6, 2018    55
1002    Week 5, 2018    406


So Basically I wanna loop each ACCT_ID like

SELECT *
FROM Fact_Table
where Week_Name between (Select Week_Begin from DATE_DIM WHERE WEEk_NAME =: v_Wknm) /* Here I will have to loop Each Week_name for Each Acct_ID */


Что я уже пробовал:

Это то, что я пробовал

DECLARE v_Init_Cnt NUMBER(10):=1;
        v_Tot_Cnt NUMBER(10);

BEGIN

    SELECT COUNT(*) INTO v_Tot_Cnt FROM DIM_DATE;

    WHILE(v_Init_Cnt <= v_Tot_Cnt)
    LOOP

    dbms_output.put_line(v_Init_Cnt);

    VARIABLE v_Id NUMBER(10);
    exec :v_Id:= v_Init_Cnt;

    dbms_output.put_line('var' || v_Id);

    SELECT * FROM FACT_TABLE 
    WHERE WEEK_NAME between (select WEEk_BEGIN FROM DIM_DATE WHERE UNIQUE_ID :=v_Init_Cnt) and (select WEEk_END FROM DIM_DATE WHERE UNIQUE_ID :=v_Init_Cnt) 

    v_Init_Cnt :=  v_Init_Cnt +1;
    END LOOP;

END;  


Я использую TOAD, на переменной exec он запрашивает у меня окно?? Как же этого избежать?

CHill60

Я вообще не понимаю, почему вы используете петлю. Базы данных Oracle основаны на множествах.

pradeep kumar

Как я это сделаю?

2 Ответов

Рейтинг:
7

CHill60

Боюсь, что у меня нет доступа к Oracle, поэтому это решение использует базовый синтаксис T-SQL.

Все, что вам нужно сделать, это объединить две таблицы на основе информации week_name, а затем сгруппировать по учетной записи и week_name ... эта работа

select A.ACCTID, B.WEEK_NAME, SUM(SALES)
from Fact A
inner join DATE_DIM B ON A.WEEK_NAME >= B.WEEK_BEGIN AND A.WEEK_NAME <= B.WEEK_END
group by A.ACCTID, B.WEEK_NAME
Это редкий случай, когда вам нужно будет использовать цикл в СУБД - я написал статью, дающую альтернативы Циклы обработки в SQL Server[^] - хотя он нацелен на SQL Server, принципы также применимы к Oracle (а также MySQL и любой другой СУБД, использующей T-SQL).

Кроме того, существуют функции, которые дают номера недель (например, см. Спросите Тома - неделя года[^] таким образом, вы могли бы просто сохранить дату на Fact таблица (как тип даты) и вычислить номер недели из этого, чтобы избежать необходимости иметь DATE_DIM стол


Рейтинг:
2

Wendelius

Я поддерживаю эту идею в решении 1 CHill60. Зачем делать цикл, когда вы можете позволить базе данных делать ВСЮ работу за вас.

Однако я хотел бы добавить несколько моментов:

В PL/SQL вам не нужно использовать точку с запятой в переменной from of. Этот синтаксис обычно используется при использовании переменной хоста. Когда вы ссылаетесь на переменные, объявленные внутри PL/SQL, вы можете использовать as-is. Рассмотреть следующее

DECLARE 
   vCriteria NUMBER;
   vResult   NUMBER;
BEGIN
   vCriteria := 5;

   SELECT COUNT(*)
   INTO vResult
   FROM SomeTable
   WHERE SomeColumn <= vCriteria;

   DBMS_OUTPUT.PUT_LINE('Result ' || vResult);
END;


Другое дело, что WEEK_NAME и сопутствующий стол. Названия недель выглядят как даты, хранящиеся в строке в формате YYYYMMDD. Если это правильно, я бы предложил использовать oracle date вместо веревки.

Если бы таблица фактов содержала даты, то вы могли бы легко извлечь номер недели, месяц, квартал и т. д. Из значения даты. Например TO_CHAR(datecolumn, 'IW') возвращает номер недели ISO для данной даты. Тип данных даты owuld дает вам гораздо больше гибкости, и, насколько я вижу, это избавит вас от необходимости в отдельных таблицах, определяющих начало недели и так далее.