Вставить в таблицу с приведением типа и условием в операторе INSERT - PullRequest
0 голосов
/ 22 мая 2019

Исходя из этого предыдущего вопроса

Я пытаюсь составить оператор вставки в Python, используя psycopg2 с некоторыми данными.Запрос прекрасно работает в консоли postgresql, но когда я пробую его из psycopg2, я получаю сообщение об ошибке.

Вот таблица, которую я хочу вставить в

create_test_table = """CREATE TABLE persons(
   name           VARCHAR,
   age            INT,
   dob            DATE,
   sex            VARCHAR);"""

Вот данные, которые я хочу вставить

d_ = {"name":"Gino", "age": "", "dob": "na", "sex": "M"}

И вот мой запрос:

cur.execute("""INSERT INTO persons (age,dob,sex,name) 
               VALUES (CASE WHEN cast(%(age)s as text) IN ('', '#', '-', '--', '??') THEN NULL ELSE %(age)s END,
                       CASE WHEN cast(%(dob)s as text) IN ('', '#', '-', '--', '??') THEN NULL ELSE %(dob)s END,
                       CASE WHEN cast(%(sex)s as text) IN ('', '#', '-', '--', '??') THEN NULL ELSE %(sex)s END,
                       CASE WHEN cast(%(name)s as text) IN ('', '#', '-', '--', '??') THEN NULL ELSE %(name)s END)""", d_)

Сообщение об ошибке:

----> 5  CASE WHEN cast(%(name)s as text) IN ('', '#', '-', '--', '??') THEN NULL ELSE %(name)s END)""", d_)

ProgrammingError: column "age" is of type integer but expression is of type text
LINE 2:                VALUES (CASE WHEN cast('' as text) IN ('', '#...
                               ^
HINT:  You will need to rewrite or cast the expression.

Возможно, это не возможно сделать в psycopg2.Любая помощь будет оценена :))

Ответы [ 2 ]

1 голос
/ 23 мая 2019

Ошибка связана с тем, что выражение CASE (то есть значение, которое вы пытаетесь вставить) равно TEXT, а столбец age - INTEGER.

Чтобы напрямую устранить ошибку, вы можете просто привести выражение к INTEGER:

CASE WHEN cast(%(age)s as text) IN ('', '#', '-', '--', '??') THEN NULL ELSE %(age)s END::INTEGER

Или

CAST(CASE WHEN cast(%(age)s as text) IN ('', '#', '-', '--', '??') THEN NULL ELSE %(age)s END AS INTEGER)

Однако, если вы на самом деле не хотите недопустимого исключения приведения, когда это поле отличается от целого числа, а не одного из значений ('', '#', '-', '--', '??'), которые вы специально исключаете, вы можете переписать этот конкретный оператор как:

CASE WHEN age::TEXT ~ '^[\d]+$' THEN age ELSE NULL END::INTEGER

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

1 голос
/ 22 мая 2019

Ваша подстановка параметров неверна.Например, вместо этого:

%(CASE WHEN cast(age as text) IN ('', '#', '-', '--', '??') THEN NULL ELSE age END)s

Вы должны иметь:

(CASE WHEN cast(%(age)s as text) IN ('', '#', '-', '--', '??') THEN NULL ELSE age END)
...