использование нескольких дат в предложении IN оператора SQL - PullRequest
2 голосов
/ 05 января 2012

У меня есть функция, которая возвращает список разделенных запятыми дат (например, «24 декабря 2011», «26 декабря 2011», «18 декабря 2011», «27 декабря 2011» ).

Я получаю это как одну строку.

Я хочу использовать эту строку для построения запроса на выборку, в котором я хочу использовать строку в предложении IN.

, например

* * 1010

Поскольку я получаю несколько дат, я хотел бы использовать все даты в своем заявлении. Как я могу написать SQL-запрос, который включает несколько дат. Пожалуйста, помогите.

Обновление: Еще одна вещь, у меня есть окно с текстовым полем и кнопка при нажатии кнопки, на которой выполняется SQL-запрос. Запрос возвращает различное количество значений столбца, в котором есть возможность выбора каждого из этих значений. Когда пользователь выбирает требуемые значения значения копируются в текстовое поле (например, «24 декабря 2011», «26 декабря 2011», «18 декабря 2011», «27 декабря 2011» , если я выбрал четыре даты ). Теперь строка Я хочу использовать эту строку в выражении SQL, где я выбираю все столбцы таблицы на основе выбранных дат, найденных в строке, т.е. значений, найденных в текстовом поле.

«Пн ДД, ГГГГ» - формат даты, возвращаемый в строке.

Я хочу запрос, похожий на Выбрать * от wfdisplaymgmt где programstartdate IN (значения даты, поступающие из текстового поля)

как мне это сделать?

Ответы [ 5 ]

2 голосов
/ 05 января 2012

Измените функцию PLSQL, чтобы она возвращала определенный пользователем тип данных TABLE OF DATE (или TIMESTAMP), и используйте IN для сопоставления значений.

Обратите внимание, что вам, вероятно, потребуется TRUNC значения даты, чтобы соответствовать им. Полдень! = Полночь!

Следующий код иллюстрирует подход.

WHENEVER SQLERROR EXIT FAIL ROLLBACK
set echo on

COLUMN programstartdate FORMAT A45
column column_value format a45

set serveroutput on

<<REINITIALIZE>>
BEGIN
  FOR DOIT IN (SELECT 'DROP TABLE ' || TABLE_NAME AS CMD FROM USER_TABLES WHERE TABLE_NAME = 'WFDISPLAYMGMT')
  LOOP
    EXECUTE IMMEDIATE DOIT.CMD;
    DBMS_OUTPUT.PUT_LINE ('Dropped test table via command: ' || doit.CMD);
  end loop;
  dbms_random.seed('This doesn''t quite feel random until I add the microseconds ' || to_char (systimestamp, 'D FF9'));
END REINITIALIZE;
/

CREATE OR REPLACE TYPE DATELIST AS TABLE OF date;
/

show errors type datelist

CREATE OR REPLACE FUNCTION GETDATES (HOWMANY IN NUMBER) RETURN DATELIST
IS
  TO_RETURN DATELIST := datelist();
BEGIN
  for stepback in 1 .. howmany
  loop
    to_return.extend();
    TO_RETURN(stepback) := trunc(sysdate - stepback);
  end loop;
  RETURN TO_RETURN;
END GETDATES;
/

show errors function getdates;

select * from table(cast (getdates (7) as datelist));

create table WFDISPLAYMGMT 
as
select 
  TRUNC(dbms_random.value (50, 10000)) as bogus_id, 
  column_value as programstartdate
from (select rownum as row_no, column_value from table(cast (getdates (30) as datelist)))
where abs (mod (row_no, 3)) = 1
;
commit;

select count (*) as generated_rows from WFDISPLAYMGMT;


select *
from WFDISPLAYMGMT
where programstartdate in (select * from table (cast (getdates (15) as datelist)));
1 голос
/ 06 января 2012

Вот немного запутанный способ сделать это только в SQL. Ниже приведен пример, который вы можете сразу запустить в своем экземпляре, чтобы проверить его:

select to_date(replace(VAL, '''', ''), 'Mon dd, yyyy') as NEWDATE
from   (with TST1 as
               (select length(DTXT) - length(translate(DTXT, REPLVAL || VALSEP, REPLVAL)) + 1 as NUMVAL
                      ,VALSEP
                      ,DTXT || VALSEP as DTXT
                from   (select replace('''Dec 24, 2011'',''Dec 26, 2011'',''Dec 18, 2011'',''Dec 27, 2011'''
                                      ,''','''
                                      ,'''|''')
                                 as DTXT
                              ,'|' as VALSEP
                              ,chr(0) as REPLVAL
                        from   dual))
        select     substr(TST1.DTXT
                         ,decode(rownum, 1, 1, instr(TST1.DTXT, VALSEP, 1, rownum - 1) + length(VALSEP))
                         ,  instr(TST1.DTXT, VALSEP, 1, rownum)
                          - decode(rownum, 1, 0, instr(TST1.DTXT, VALSEP, 1, rownum - 1))
                          - 1)
                     as VAL
        from       TST1
        connect by level <= TST1.NUMVAL)

То, что он делает, это берет ваши разделенные запятыми даты и преобразует их в отдельные записи, которые затем могут быть преобразованы в тип даты. В вашем сценарии вы можете заменить подзапрос, который выбирает двойной, вашей функцией, например ::100100

select *
from wfdisplaymgmt
where programstartdate IN (
select to_date(replace(VAL, '''', ''), 'Mon dd, yyyy') as NEWDATE
...
    select replace(myfunctioncall()
                   ,''','''
                   ,'''|''')
            as DTXT
          ,'|' as VALSEP
          ,chr(0) as REPLVAL
    from   dual
...

Что я сделал здесь, так это заменил разделители запятых на разделители каналов, так как запятая появляется в формате даты. Кроме того, я добавил разделитель канала в конец текста, чтобы включить последнее значение. Если вам нужна дополнительная информация о том, что делает каждый бит, добавьте комментарий.

0 голосов
/ 07 января 2012

Рассмотрите возможность создания новой функции (или замены старой), которая возвращает вам таблицу (массив) данных вместо списка csv в одной строке.На самом деле будет намного проще использовать функцию осмысленно:

-- Create types

CREATE TYPE t_tf_row AS OBJECT (
  id           NUMBER,
  dte         date
);
/

CREATE TYPE t_tf_tab IS TABLE OF t_tf_row;
/

-- Build the table function itself.
CREATE OR REPLACE FUNCTION get_tab_tf (p_rows IN NUMBER) RETURN t_tf_tab AS
  l_tab  t_tf_tab := t_tf_tab();
  l_dte date;
BEGIN
  -- create rows
  FOR i IN 1 .. p_rows LOOP
    l_dte := sysdate - i;
    l_tab.extend;
    l_tab(l_tab.last) := t_tf_row(i, l_dte);
  END LOOP;

  RETURN l_tab;
END;
/

-- test new function, selecting 20 dates

select * from MY_TABLE
where MY_DATE in (select dte from table(get_tab_tf(20)));

Конечно, в вашей версии функции создайте даты так, как вам нужно.Также обратите внимание, что вы могли бы также сделать конвейерную версию, но я предполагаю, что список дат является разумным по длине.

0 голосов
/ 05 января 2012

Принимая оракула, и я в лучшем случае заржавел от этой технологии

select * 
from wfdisplaymgmt 
where  instr(your_function_that_delivers_dates()
             , TO_CHAR(programstartdate,'MON DD, YYYY')) > 0

Не ожидайте высокой производительности для больших таблиц, потому что план запросов не будет использовать какой-либо индекс, вместо этого он будет выполнять сканирование полной таблицы

На основании найденной информации здесь

0 голосов
/ 05 января 2012

вы можете использовать функцию EXECUTE () для выполнения строки как оператора sql, которая будет работать, иначе вы можете просто разбить строку дат на переменную таблицы и затем использовать ее в переменной таблицы.Обе работы, я думаю, что табличная переменная, вероятно, является лучшим решением.

...