Преобразования даты SQL - PullRequest
       6

Преобразования даты SQL

0 голосов
/ 20 декабря 2018

Я получил данные в Excel, и столбец DATE (с именем ALL_PERIODS) имеет значение STRING и имеет следующий формат:

JFM 14 - W / E 04/05/14

январь, февраль, март 2014 г., выходные дни 04/05/14

Мне нужно разделить этот столбец на три новых столбца: DATE_ (DATE), YEAR_ (INT), QUARTER_ (INT),поэтому я написал эти преобразования:

ДАТА столбца:

ALTER TABLE MY_TABLE 
   ADD DATE_TEMP VARCHAR2 (128);
UPDATE MY_TABLE 
   SET DATE_TEMP = SUBSTR(ALL_PERIODS, -2, 2);
UPDATE MY_TABLE 
   SET DATE_TEMP = REPLACE(DATE_TEMP, '/',  '');
UPDATE MY_TABLE 
   SET DATE_TEMP = to_char(to_date(DATE_TEMP, 'mmddyyyy'), 'yyyy-mm-dd');
UPDATE MY_TABLE 
   SET DATE_TEMP = REPLACE(DATE_TEMP, '00',  '20');
UPDATE MY_TABLE 
   SET DATE_TEMP = TO_DATE(DATE_TEMP, 'YYYY-MM-DD');
ALTER TABLE MY_TABLE 
ADD DATE_ DATE;
UPDATE MY_TABLE 
   SET DATE_ = DATE_TEMP;
ALTER TABLE MY_TABLE 
   DROP COLUMN DATE_TEMP;

ГОД столбца:

ALTER TABLE MY_TABLE
    ADD YEAR_TEMP VARCHAR2(128 BYTE);
UPDATE MY_TABLE
    SET YEAR_TEMP =  SUBSTR(ALL_PERIODS, 8, 4);
ALTER TABLE MY_TABLE
    ADD YEAR_ NUMBER(4);
UPDATE MY_TABLE
    SET YEAR_ =  YEAR_TEMP;
UPDATE MY_TABLE
    SET YEAR_ = CONCAT('20', YEAR_);
ALTER TABLE MY_TABLE
    DROP COLUMN YEAR_TEMP;

Квартал столбца:

ALTER TABLE MY_TABLE 
    ADD QUARTER NUMBER(1);
UPDATE MY_TABLE
    SET QUARTER_ = 4
        WHERE DATE_ = '30-DEC-17';
...and the same with other 3 quarters

Это как-то работает, но я думаю, что это не эффективно (я не очень продвинут в SQL, и я все еще учусь), и операции обновления выполняются слишком медленно, поэтому я хотел бы преобразовать столбец ALL_PERIODS, покавставка данных в новую таблицу с тремя необходимыми столбцами.

Подскажите, пожалуйста, как должна выглядеть INSERT?Спасибо Н.

Ответы [ 4 ]

0 голосов
/ 20 декабря 2018

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

SETUP

INSERT INTO myTable (baseDate)
SELECT 'JFM 14 - W/E 04/05/14' FROM dual
UNION ALL 
SELECT 'AMJ 14 - W/E 06/05/14' FROM dual
UNION ALL 
SELECT 'JAS 14 - W/E 09/05/14' FROM dual
UNION ALL 
SELECT 'OND 14 - W/E 12/05/14' FROM dual
UNION ALL 
SELECT 'JFM 15 - W/E 04/05/15' FROM dual
UNION ALL 
SELECT 'AMJ 15 - W/E 06/05/14' FROM dual
UNION ALL 
SELECT 'JAS 15 - W/E 09/05/14' FROM dual
UNION ALL 
SELECT 'JAS 49 - W/E 03/05/49' FROM dual
UNION ALL 
SELECT 'JAS 50 - W/E 04/05/50' FROM dual

В следующей строке SELECT проверяется формат даты по умолчанию для вашего сервера.Это значение может повлиять на интерпретацию даты вашей строки.

SELECT value FROM v$nls_parameters WHERE parameter ='NLS_DATE_FORMAT';
| VALUE     |
| :-------- |
| DD-MON-RR |

После того, как я вставлю значения, я могу просто обновить свою таблицу на основе этого значения.

UPDATE myTable
SET
    DATE_ = 
        TO_DATE(
            SUBSTR(baseDate,INSTR(baseDate, ' ', -1)+1,8) -- Find last space to get end of string date value.
            , 'MM/DD/RR'
        )  /* TO_DATE already creates date object. RR mask rounds to 4-digit year. (49 = 1949, 50 = 2050) */
    , QUARTER_ = 
        CASE SUBSTR(baseDate, 1, 3)
            WHEN 'JFM' THEN 1 
            WHEN 'AMJ' THEN 2
            WHEN 'JAS' THEN 3
            WHEN 'OND' THEN 4
        END

Для DATE_ вам не нужно делать TO_CHAR, так как TO_DATE преобразует вашу строку в значение даты для столбца даты в БД,Ваша база данных на самом деле не заботится о том, выглядит ли дата как «гггг-мм-дд», потому что она так или иначе не видит ее.Я использовал маску RR, чтобы преобразовать двухзначное значение года в четырехзначное значение года.Это переведет 49 AS 2049 и 50 как 1950.Если вам не нужны даты 19xx, вы можете просто использовать YY.Если вам нужно, вы можете выполнить дополнительную проверку вашего строкового значения, чтобы убедиться, что оно может быть преобразовано в дату.

Для QUARTER_, это просто простое выражение CASE, которое интерпретирует вашу строку четверти вчисло.

Затем я обновляю YEAR_ на основе значения даты в DATE_.Это гарантирует, что мой год остается неизменным в ряду.Это также может быть выполнено при первоначальном обновлении, если значение извлечено из базовой строки.

UPDATE myTable
SET YEAR_ = EXTRACT ( YEAR FROM DATE_ )

Это дает нам:

BASEDATE              | DATE_     | YEAR_ | QUARTER_
:-------------------- | :-------- | ----: | -------:
JFM 14 - W/E 04/05/14 | 05-APR-14 |  2014 |        1
AMJ 14 - W/E 06/05/14 | 05-JUN-14 |  2014 |        2
JAS 14 - W/E 09/05/14 | 05-SEP-14 |  2014 |        3
OND 14 - W/E 12/05/14 | 05-DEC-14 |  2014 |        4
JFM 15 - W/E 04/05/15 | 05-APR-15 |  2015 |        1
AMJ 15 - W/E 06/05/14 | 05-JUN-14 |  2014 |        2
JAS 15 - W/E 09/05/14 | 05-SEP-14 |  2014 |        3
JAS 49 - W/E 03/05/49 | 05-MAR-49 |  2049 |        3
JAS 50 - W/E 04/05/50 | 05-APR-50 |  1950 |        3

Поскольку DATE_ является фактическим объектом даты, на дисплее вы можете отформатировать его с любой маской.

db <> fiddle здесь

0 голосов
/ 20 декабря 2018

DDL-операторы (столбец добавления / удаления) являются медленными и ненужными.Вы не должны изменять определение таблицы при вставке данных!

Я бы вставил 3 столбца следующим образом (замените строку даты, которую я использовал, на действительное значение ALL_PERIODS):

INSERT INTO MY_TABLE (DATE_, YEAR_, QUARTER_)
TO_DATE(SUBSTR('JFM 14 - W/E 04/05/14', -8), 'dd/mm/yy'),
EXTRACT(YEAR FROM TO_DATE(SUBSTR('JFM 14 - W/E 04/05/14', -2), 'yy')),
-- OR SHORTER IF ALWAYS IN THE 2000: TO_NUMBER(SUBSTR('JFM 14 - W/E 04/05/14', -2)) + 2000
DECODE(SUBSTR('JFM 14 - W/E 04/05/14',1,3), 'JFM', 1, 'AMJ', 2, 'JAS', 3, 'OND', 4);

С уважением

0 голосов
/ 20 декабря 2018

Если ALL_PERIODS уже загружен в таблицу?
А дополнительные столбцы для расчета уже добавлены в таблицу?

Тогда достаточно 1 обновления.

UPDATE MY_TABLE
SET 
 DATE_ = TO_DATE(SUBSTR(RTRIM(ALL_PERIODS),-8),'MM/DD/YY')
,YEAR_ = 2000+SUBSTR(ALL_PERIODS,5,2)
,QUARTER_ = DECODE(SUBSTR(ALL_PERIODS,1,3), 'JFM', 1, 'AMJ', 2, 'JAS', 3, 'OND', 4)
WHERE ALL_PERIODS IS NOT NULL 
  AND DATE_ IS NULL

Тест на db <> fiddle здесь

0 голосов
/ 20 декабря 2018
INSERT INTO my_table (COL1, COL2, ... DATE_, QUARTER_, YEAR_)
SELECT sr.COL1, sr.COL2, .... 
TO_DATE(TO_CHAR(TO_DATE(SUBSTR(sr.ALL_PERIODS, -8), 'mm/dd/yy'), 'YYYY-MM-DD'), 'YYYY-MM-DD') DATE_,
CASE SUBSTR(sr.ALL_PERIODS, 1, 3)
WHEN 'JFM' THEN 1 
WHEN 'AMJ' THEN 2
WHEN 'JAS' THEN 3
WHEN 'OND' THEN 4
END QUARTER_,
'20'||SUBSTR(sr.ALL_PERIODS, 5,2) YEAR_,
FROM SOURCE_TABLE sr
[WHERE sr.COL99 = 'Y'];
...