2015-12-03 3 views
1

В Postgres 9.4.5 следующий запрос не работает.Postgres Неверный код исполнения

SELECT * FROM (
    SELECT M.NAME, M.VALUE AS V 
    FROM METRICS AS M, METRICATTRIBUTES AS A 
    WHERE M.NAME=A.NAME AND A.ISSTRING='FALSE' 
    ) AS S1 
WHERE CAST(S1.V AS NUMERIC)<0 

Я получаю сообщение об ошибке, как:

invalid input syntax for type numeric: "astringvalue" 

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

METRICS - это таблица метрик, пары значений. Значения сохраняются как строки, а некоторые значения поля VALUE - это строки. В таблице METRICATTRIBUTES указаны те метрические имена, которые могут иметь строковые значения. Я заполнил таблицу METRICATTRIBUTES из анализа таблицы METRICS.

Чтобы проверить, я побежал ...

SELECT * FROM (
    SELECT M.NAME, M.VALUE AS V 
     FROM METRICS AS M, METRICATTRIBUTES AS A 
    WHERE M.NAME=A.NAME AND A.ISSTRING='FALSE' 
    ) AS S1 
WHERE S1.V LIKE 'a%' 

Это не возвращает значения (как я бы ожидать). Ошибка, похоже, находится в плане выполнения. Что выглядит примерно так (извините, я должен был палец жира этого)

1 -> HAS JOIN 
2 HASH COND: ((M.NAME::TEXT=(A.NAME)::TEXT)) 
3  SEQ SCAN ON METRICS M 
4  FILTER: ((VALUE)::NUMERIC<0::NUMERIC) 
5 -> HASH 
6  -> Seq Scan on METRICATTRIBUTES A 
7  Filter: (NOT ISSTRING) 

Я не эксперт по этому (только 1 неделю опыта Postgres), но это выглядит как Postgres пытается применить бросок (линии 4) перед тем, как применить условие соединения (строка 2). Делая это, он попытается применить приведение к недопустимым строковым значениям, что именно то, чего я пытаюсь избежать!

Написание этого с явным соединением не имело никакого значения. Написание его как одного оператора выбора было моей первой попыткой, никогда не ожидавшей такого типа проблемы. Это тоже не сработало.

Любые идеи?

+0

Порядок, в котором условия не гарантируются, и СУБД может свободно вводить внешнее условие в производную таблицу (эффективно исключая производную таблицу полностью) по соображениям эффективности. Btw: вы должны прекратить использовать те древние неявные объединения в предложении 'where' и использовать явный оператор' JOIN'. –

ответ

0

Как вы можете видеть из вашего плана, таблицы METRICS сканируется в полном объеме (Seq Scan) и фильтруют с условием: CAST(S1.V AS NUMERIC)<0 -join не ограничивает сферу вообще.

Очевидно, что у вас есть несколько строк, содержащих нечисловые данные в METRICS.VALUE. Проверьте таблицу для таких строк, как это:

SELECT * FROM METRICS 
WHERE NOT VALUE ~ '^([0-9].,e)*$' 

Примечания, что трудно уловить все возможные комбинации с регулярным выражением, поэтому проверить этот родственный вопрос: isnumeric() with PostgreSQL

Имени VALUE для столбца не хорошо, как это слово is a reserved one.

Edit: Если вы абсолютно уверены, что присоединились таблицы будет производить требуемые VALUE -s, чем вы можете использовать CTEs, которые имеют функцию оптимизации забор в PostgreSQL:

WITH S1 AS (
    SELECT M.NAME, M.VALUE AS V 
     FROM METRICS AS M 
     JOIN METRICATTRIBUTES AS A USING (NAME) 
    WHERE A.ISSTRING='FALSE' 
) 
SELECT * 
    FROM S1 
WHERE CAST(S1.V AS NUMERIC)<0; 
+0

I KNOW У меня есть текстовые значения в таблице METRICS. Но я также знаю, что у меня нет текстовых значений для тех записей, которые соответствуют записи в таблице METRICATTRIBUTES, где ISSTRING = FALSE.Я сделал таблицу METRICATTRIBUTES с единственной целью - отфильтровать строковые значения из таблицы METRICS. Проблема в том, что порядок исполнения сорвал мои планы. –

+0

@EHorowitz, чем вы можете использовать 'WITH' для управления порядком соединения. – vyegorov

Смежные вопросы