Oracle случайное время и интервал - PullRequest
0 голосов
/ 11 июля 2020

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

Представьте себе тюремного охранника, который должен ходить по тюрьме и проверять каждую камеру. Расписание запустится в случайное время MMDDYYYY HH24: MI, а затем будет от 6 до 10 минут, чтобы проверить следующую ячейку, после этого 6-10 минут, чтобы проверить ячейку, после этого и так далее, и так до завершения расписания.

Позвольте мне проиллюстрировать на простом примере.

Schedule_id location_id Schedule_time

1100 07132020 16: 10: 00

- начало расписания

1 103 07132020 16: 07: 00

- охрана должна быть в ячейке 103 к 16: 07

1110 07132020 16: 16: 00

- охрана должна быть в позиции 110 к 16:16

Поскольку я произвольно сгенерировал 3 строки для расписания 1, это завершено, я создаю следующее расписание.

- начало расписания, но скажем, я произвольно СОЗДАЛ 5 строк для этого расписания.

2 102 07132020 23: 46: 00

- охранник должен быть в позиции 102 к 23: 46

2 104 07132020 23: 56: 00

- охранник должен быть на позиции 104 к 23: 56

- ПОДОЖДИТЕ !! Я сгенерировал 5 строк для расписания 2, но следующий интервал пересечет полночь, поэтому я останавливаюсь на 2 строках, а затем go, чтобы создать следующее расписание в каком-то случайном HH24: MI, но MMDDYYYY все равно будет тем же самым 07132020.

СТОП-ПРОБЕЛ: либо мы заполнили строки значениями времени, либо он не может пересечь полночь !!

- начало нового расписания. Обратите внимание на то же MMDDYYYY

3 223 07132020 02: 04: 00

3 143 07132020 02: 11: 00

3 46 07132020 02: 17: 00

Ваш первый пример был почти готов, за исключением того, что не было НЕОБХОДИМОСТИ ОСТАНОВКИ, чтобы предотвратить его пересечение полуночи и создание следующего расписания.

У меня тоже есть таблица местоположений, в которой я хочу случайным образом выбрать location_id, но я не могу используйте dbms_random, поскольку значения не нумеруются последовательно. Я постараюсь понять это. Я упоминаю об этом, чтобы завершить сценарий.

 CREATE TABLE schedule_hdr AS
SELECT level AS schedule_id,
   'Schedule ' || level AS schedule_name

 FROM   dual
CONNECT BY level <= 10;



CREATE TABLE  locations(
location_id NUMBER(4), 
location_name VARCHAR2(30)
);

INSERT INTO locations (
location_id, 
location_name 
)
VALUES 
(46, 'Door 1');

INSERT INTO locations (
location_id, 
location_name 
)
VALUES 
(143, 'Door 2');

INSERT INTO locations (
location_id, 
location_name 
)
VALUES 
(223, 'Door 3');

WITH random_times (     schedule_id,    schedule_name, datetime, lvl ) AS (
SELECT schedule_id,
     schedule_name, 
     TRUNC(sysdate)
     + NUMTODSINTERVAL( FLOOR(DBMS_RANDOM.VALUE(0,23*60)), 'MINUTE' ),
     1
  FROM   schedule_hdr
 UNION ALL
 SELECT schedule_id,
     schedule_name, 
     datetime + NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(6,11)), 'MINUTE'),
     lvl + 1
  FROM   random_times
  WHERE  lvl < 5
)
SELECT schedule_id,
   schedule_name,
   datetime
FROM   random_times
   ORDER BY schedule_id, datetime;

Моя первая попытка, но дата есть. всегда случайный и без интервала

WITH rws  as (     select level rn from   dual connect by level <= 5 ), 
   scheds as ( select sh.*, round (dbms_random.value(1,5) ) n from schedule_hdr sh )
  select   schedule_id,
  TRUNC(sysdate) + DBMS_RANDOM.value(0,86400)/86400
  from   rws 
  join   scheds s  on rn <= n
  Order by schedule_id;

Ответы [ 5 ]

0 голосов
/ 12 июля 2020

Вы можете использовать NUMTODSINTERVAL( <random_amount>, 'MINUTE' ) для создания интервала всего в минутах. Соедините это с предложением факторинга рекурсивного подзапроса, и вы можете сгенерировать 5 строк для каждой строки в schedule_hdr:

WITH random_times ( schedule_id, schedule_name, datetime, lvl ) AS (
  SELECT schedule_id,
         schedule_name, 
         TRUNC(sysdate)
         + NUMTODSINTERVAL( FLOOR(DBMS_RANDOM.VALUE(0,19*60)), 'MINUTE' ),
         1
  FROM   schedule_hdr
UNION ALL
  SELECT schedule_id,
         schedule_name, 
         datetime + NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(6,11)), 'MINUTE'),
         lvl + 1
  FROM   random_times
  WHERE  lvl < 5
)
SELECT schedule_id,
       schedule_name,
       datetime
FROM   random_times
ORDER BY schedule_id, datetime;

Итак, для ваших тестовых данных:

CREATE TABLE schedule_hdr (schedule_id, schedule_name) AS
SELECT 1, 'Schedule 1' FROM DUAL UNION ALL
SELECT 2, 'Schedule 2' FROM DUAL;

Это выходы:

SCHEDULE_ID | SCHEDULE_NAME | DATETIME           
----------: | :------------ | :------------------
          1 | Schedule 1    | 2020-07-11 05:13:00
          1 | Schedule 1    | 2020-07-11 05:23:00
          1 | Schedule 1    | 2020-07-11 05:32:00
          1 | Schedule 1    | 2020-07-11 05:38:00
          1 | Schedule 1    | 2020-07-11 05:45:00
          2 | Schedule 2    | 2020-07-11 10:56:00
          2 | Schedule 2    | 2020-07-11 11:02:00
          2 | Schedule 2    | 2020-07-11 11:09:00
          2 | Schedule 2    | 2020-07-11 11:19:00
          2 | Schedule 2    | 2020-07-11 11:29:00

db <> fiddle здесь

Обновить

Мне ВСЕГДА нужно, чтобы MMDDYYYY был одинаковым для всех строк. Таким образом, можно настроить код для сброса времени начала при изменении schedule_id.

Создайте один набор строк и CROSS JOIN с вашей таблицей:

WITH random_times ( datetime, lvl ) AS (
  SELECT TRUNC(sysdate)
         + NUMTODSINTERVAL( FLOOR(DBMS_RANDOM.VALUE(0,19*60)), 'MINUTE' ),
         1
  FROM   DUAL
UNION ALL
  SELECT datetime + NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(6,11)), 'MINUTE'),
         lvl + 1
  FROM   random_times
  WHERE  lvl < 5
)
SELECT sh.schedule_id,
       sh.schedule_name,
       rt.datetime
FROM   schedule_hdr sh
       CROSS JOIN random_times rt
ORDER BY schedule_id, datetime;

Это дает :

SCHEDULE_ID | SCHEDULE_NAME | DATETIME           
----------: | :------------ | :------------------
          1 | Schedule 1    | 2020-07-11 13:43:00
          1 | Schedule 1    | 2020-07-11 13:49:00
          1 | Schedule 1    | 2020-07-11 13:56:00
          1 | Schedule 1    | 2020-07-11 14:03:00
          1 | Schedule 1    | 2020-07-11 14:10:00
          2 | Schedule 2    | 2020-07-11 13:43:00
          2 | Schedule 2    | 2020-07-11 13:49:00
          2 | Schedule 2    | 2020-07-11 13:56:00
          2 | Schedule 2    | 2020-07-11 14:03:00
          2 | Schedule 2    | 2020-07-11 14:10:00

db <> fiddle здесь

Обновление 2

WITH indexed_locations ( num, name ) AS (
  SELECT ROW_NUMBER() OVER ( ORDER BY DBMS_RANDOM.VALUE(), id ),
         name
  FROM   locations
),
random_times ( schedule_id, schedule_name, datetime, lvl, max_lvl, max_doors ) AS (
  SELECT schedule_id,
         schedule_name,
         TRUNC(sysdate)
         + NUMTODSINTERVAL( FLOOR(DBMS_RANDOM.VALUE(0,24*60)), 'MINUTE' ),
         1,
         FLOOR(DBMS_RANDOM.VALUE(1,11)),
         ( SELECT COUNT(*) FROM locations )
  FROM   schedule_hdr
UNION ALL
  SELECT schedule_id,
         schedule_name,
         datetime + NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(6,11)), 'MINUTE'),
         lvl + 1,
         max_lvl,
         max_doors
  FROM   random_times
  WHERE  lvl < max_lvl
)
SELECT rt.schedule_id,
       rt.schedule_name,
       rt.datetime,
       il.name AS door_name
FROM   random_times rt
       INNER JOIN indexed_locations il
       ON ( FLOOR( DBMS_RANDOM.VALUE( 1, rt.max_doors + 1 ) ) = il.num )
WHERE  rt.datetime < TRUNC( SYSDATE ) + INTERVAL '1' DAY
ORDER BY schedule_id, datetime;

Выводы:

SCHEDULE_ID | SCHEDULE_NAME | DATETIME            | DOOR_NAME
----------: | :------------ | :------------------ | :--------
          1 | Schedule 1    | 2020-07-12 23:31:00 | Door 4   
          1 | Schedule 1    | 2020-07-12 23:38:00 | Door 1   
          1 | Schedule 1    | 2020-07-12 23:45:00 | Door 6   
          1 | Schedule 1    | 2020-07-12 23:51:00 | Door 2   
          2 | Schedule 2    | 2020-07-12 10:15:00 | Door 4   
          2 | Schedule 2    | 2020-07-12 10:22:00 | Door 1   
          2 | Schedule 2    | 2020-07-12 10:30:00 | Door 1   
          2 | Schedule 2    | 2020-07-12 10:37:00 | Door 6   
          3 | Schedule 3    | 2020-07-12 21:59:00 | Door 4   
          3 | Schedule 3    | 2020-07-12 22:06:00 | Door 1   
          3 | Schedule 3    | 2020-07-12 22:13:00 | Door 1   
          3 | Schedule 3    | 2020-07-12 22:21:00 | Door 4   

db <> fiddle здесь

0 голосов
/ 11 июля 2020

Я бы сделал так:

select 
    TRUNC(TRUNC(sysdate) + dbms_random.value(0, 1) * INTERVAL '19:00' HOUR TO MINUTE, 'MI') 
from dual;
0 голосов
/ 11 июля 2020

Это должно делать то, что вы хотите:

select trunc(sysdate) + floor(dbms_random.value(0, 1) * 19*60*60) * interval '1' second
from dual;

Это генерирует количество секунд, а затем добавляет их к дате.

Один из способов узнать время - это преобразовать значение в строку:

select to_char(trunc(sysdate) + floor(dbms_random.value(0, 1) * 19*60*60) * interval '1' second, 'YYYY-MM-DD HH24:MI:SS')
from dual
0 голосов
/ 11 июля 2020

Хорошо, вот и вся последовательность:

--seconds 0    
--minutes increment: 6-10    
--start: 00:00 - 18:59    
--start integer between 0 and 19*60-1

with first_value as (
select trunc(sysdate) + (abs(mod(dbms_random.random, (19*60-1)))/(24*60)) first_date_value from dual
),
other_values (next_date_value, lvl) as (
select first_date_value, 0 from first_value fv
union all
select ov.next_date_value + (round(dbms_random.value(6,10)) / (24*60)), ov.lvl + 1 from first_value fv join other_values ov on ov.next_date_value < to_date(to_char(sysdate, 'dd.mm.yyyy') || ' 18:49', 'dd.mm.yyyy hh24:mi') 
)
select * from other_values;

Он использует CTE для создания первого значения, а затем предоставляет список до тех пор, пока другие значения не станут возможными. Я вычисляю случайную минуту от 0 до 18 * 60 + 59 для начального значения. Затем у меня есть рекурсивный CTE, который увеличивает предыдущее значение от 6 до 10 минут. Есть условие остановки рекурсии в 18:49. Следующее приращение должно по-прежнему позволять значение меньше 18: 59

0 голосов
/ 11 июля 2020

Заявление об ограничении ответственности: я разработчик C# / MS- SQL и никогда не использовал Oracle SQL или Oracle систему, поэтому прошу прощения за мой синтаксис.

Перед генерацией случайного числа необходимо установить начальное число. Обычно отметка времени в MS является хорошим начальным значением для генерации случайных чисел, поскольку она будет отличаться при каждом выполнении ( Источник ):

DBMS_RANDOM.seed (val => TO_CHAR(SYSTIMESTAMP,'YYYYDDMMHH24MISSFFFF'));

Затем, когда вы генерируете дату. Добавляя дату с номером, я не уверен, что вы можете просто +. Если да, простите меня, в противном случае попробуйте numToDSInterval ( Источник ):

TRUNC(sysdate) + numToDSInterval( DBMS_RANDOM.value(0,86400)/86400, 'second' )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...