Какой индекс для подстроки запроса по типу даты? - PullRequest
3 голосов
/ 12 марта 2020

Привет! Я пытаюсь сделать запрос, чтобы напечатать пользователей, которые выполняют действия с указанным c месяцем ORACLE SQL РАЗРАБОТЧИК.

Вот таблицы:

CREATE TABLE USUARIO2 (
    CODIGO NUMBER(10) CONSTRAINT USUARIO_PK PRIMARY KEY,
    NOMBRE VARCHAR(50) CONSTRAINT NOM_USUARIO_NN NOT NULL,
    TELEFONO VARCHAR2(12),
    DIRECCION VARCHAR2(100)
);

CREATE TABLE SACA (
    COD_USUARIO NUMBER(10),
    COD_EJEMPLAR NUMBER(10),
    FECHA_PRES DATE DEFAULT SYSDATE,
    FECHA_DEV DATE,
    CONSTRAINT SACA_PK PRIMARY KEY (COD_USUARIO, COD_EJEMPLAR, FECHA_PRES),
    CONSTRAINT USUARIO_FK FOREIGN KEY (COD_USUARIO) REFERENCES USUARIO2(CODIGO) ON DELETE CASCADE,
    CONSTRAINT EJEMPLAR_FK FOREIGN KEY (COD_EJEMPLAR) REFERENCES EJEMPLAR(CODIGO) ON DELETE CASCADE
);

Вот значения SACA:

INSERT INTO SACA VALUES (123,778899, '01-01-2017','02-05-2017');
INSERT INTO SACA VALUES (123,112233, '01-01-2017','02-05-2017');
INSERT INTO SACA VALUES (234,882143,'04-01-2017','04-07-2017');
INSERT INTO SACA VALUES (234,777722,'04-01-2017','04-07-2017');
INSERT INTO SACA VALUES (345,976543, '01-01-2017','02-05-2017');
INSERT INTO SACA VALUES (456,446733,'04-01-2017','04-07-2017');
INSERT INTO SACA VALUES (567,778899, '01-01-2017','02-05-2017');
INSERT INTO SACA VALUES (890,222266,'04-01-2017','04-07-2017');

И это запрос. Я хотел бы опросить пользователей, которые получают книгу на определенный c месяц (05) из столбца FECHA_DEV. Итак, вот запрос:

SELECT usuario2.nombre
FROM usuario2
JOIN saca ON usuario2.codigo=saca.cod_usuario WHERE SUBSTR(FECHA_DEV,3,5) IN ('05');

Запрос пуст, но если изменить значения и запросить с первой и последней позиции, он работает.

¿Так какие же индексы месяца для формата DATE?

Ответы [ 5 ]

4 голосов
/ 12 марта 2020

Я предполагаю Oracle из-за использования типа данных number и ссылки sysdate.


Не используйте строковые функции для значений DATE. В тот или иной момент произойдет сбой (например, на моем компьютере SUBSTR(sysdate,3,5) возвращает -MAR-, а не 03).

Лучше извлечь месяц как число.

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

SELECT usuario2.nombre
FROM usuario2
   JOIN saca ON usuario2.codigo=saca.cod_usuario 
WHERE extract(month from FECHA_DEV) = 5;

Для приведенного выше индекса потребуется такой индекс:

create index idx_fecha_dev_month on SACA  ( extract(month from FECHA_DEV)  );

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

3 голосов
/ 12 марта 2020

¿Итак, каковы индексы месяца для формата DATE?

Суть вопроса ошибочна, поскольку DATE не имеет формата, поскольку она хранится внутри как 7 байт (соответственно: век, год века, месяц, день месяца, час, минута и секунда), поэтому универсального строкового представления типа данных DATE не существует.

Функция SUBSTR( string, start_character, length ) принимает:

  • Строка в качестве первого аргумента;
  • Начальным индексом подстроки является второй аргумент и первый символ в строке имеют индекс 1 (а не 0); и
  • Длина возвращаемой подстроки в качестве третьего аргумента.

Итак, первые ошибки состоят в том, что, если вы принимаете формат DD-MM-RR и хотите 2- длинная символьная подстрока, начинающаяся с 4-го символа строки, затем 2-й и 3-й аргументы должны быть 4, 2, а не 3, 5.

Первое, что Oracle сделает, когда вы передадите DATE в качестве первого аргумента нужно попытаться неявно преобразовать DATE в строку, и ваш вызов функции будет эффективным:

SUBSTR(
  TO_CHAR(
    fecha_dev,
    ( SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_DATE_FORMAT' )
  ),
  4,
  2
)

Значение по умолчанию NLS_DATE_FORMAT зависит от NLS_TERRITORY настройки, чтобы вы не получали согласованное значение между пользователями в разных частях света (т. е. в Испании по умолчанию установлено значение DD/MM/RR, тогда как в Америке это DD-MON-RR, а месяц отображается в виде символов, а в Швеции - * 1040). * и получение 4-го и 5-го символов дало бы в прошлом году ди git и дефис).

Даже если все ваши пользователи находятся на одной территории, нет гарантии, что они не будут устанавливать свои собственные Параметры ssion, так как любой пользователь может выполнить команду, чтобы изменить свой сеанс, чтобы изменить его. Например:

ALTER SESSION SET NLS_DATE_FORMAT = 'DD HH24MISS MONRR';

(и, да, этот формат даты используется в некоторых настройках)

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

Если вы хотите использовать SUBSTR, вам следует явно преобразовать дату в строку и указать модель формата:

WHERE SUBSTR( TO_CHAR( fecha_dev, 'DD-MM-RR' ), 4, 2 ) IN ( '05' )

Однако, если вы собираетесь это сделать, вы можете просто пропустить SUBSTR и просто вывести месяц:

WHERE TO_CHAR( fecha_dev, 'MM' ) = '05'

Или вы можете использовать EXTRACT:

WHERE EXTRACT( MONTH FROM fecha_dev ) = 5
1 голос
/ 12 марта 2020

Похоже, вы хотите, чтобы все записи с FECHA_DEV в мае месяце.

Если вы хотите май во всех годах, используйте

WHERE MONTH(FECHA_DEV) = 5

Но это выражение WHERE должно вычисляться функция МЕСЯЦ для каждого ряда. Так что вы можете использовать индекс для этого выражения.

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

WHERE FECHA_DEV >= '2017-05-01' AND FECHA_DEV < '2017-06-01'

Затем индекс по датам в поможет столбец FECHA_DEV, поскольку он позволит серверу сканировать диапазон индекса.

Pro tip Старайтесь избегать обработки дат как символьных строк. SQL предлагает все виды классных арифметических дат c, которые можно использовать при обработке дат как типов DATE или DATETIME.

Чтобы отобразить значения DATE или DATETIME, используйте DATE_FORMAT ().

1 голос
/ 12 марта 2020

В SUBSTR последний параметр предназначен для length из положения, определенного вторым параметром:

WHERE SUBSTR(FECHA_DEV, 3, 2) IN ('05'); -- changed 5 to 2

Однако вы можете использовать extract:

WHERE extract(month FROM FECHA_DEV) = 5
0 голосов
/ 12 марта 2020

FECHA_DEV - это столбец даты, и вы не должны рассматривать его как строку. Используйте EXTRACT(), чтобы получить месяц:

WHERE EXTRACT(month FROM FECHA_DEV) = 5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...