Как создать столбец в postgres из значений и выборок на основе других столбцов?

Я хочу создать новое поле (или два) в моей таблице, которое является конкатенацией других полей, что кажется относительно простым. Но что такое case синтаксис или if/when синтаксис, который я бы использовал для создания следующих полей (GPA_TXT и newfield)?

логика такова: каждый GPA должен быть #.#, каждое новое поле должно быть:

name & "-" & GPA_TXT & (
    case where GPA_TXT > 3.3
        set newfield = newfield & 'GradeA',
    case where GPA_TXT >2.7 and GPA_TXT < 3.3
        set newfield = newfield & "GradeB",
    etc...
)

например:

name         major     GPA(num) GPA_TXT   [newfield]
Bob          sci       2        02.0      Bob-sci-GradeC-02.0
Jane         chem      3.1      03.1      Jane-chem-GradeB-03.1
Charlie      phys      3.7      03.7      Charlie-phys-GradeA-03.7
Garfield     food      0        00.0      Garfield-food-GradeF-00.0

Итак, я думаю, у меня есть два вопроса здесь:

  1. как создайте поле GPA TXT.
  2. как написать оператор case для вычисления поля в соответствии со значениями в других полях.

если кто-нибудь может связать меня с ресурсом с примерами или объяснить, я был бы очень признателен! Я просматриваю документацию, но не получаю ничего без примеров.

3 ответов


важное примечание: Я бы создал посмотреть на основе текущей таблицы и избежать добавления новых столбцов, как они будут денормализация схемы. Подробнее здесь.

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

  • в форме GPA_TXT поле вы можете использовать to_char() функция: to_char(gpa, 'FM09.0') (the FM будет избегать пространства перед результирующим string);
  • для второго поля я бы использовал GPA, а не GPA_TXT для числового сравнения. Вы можете проверить CASE конструкции документы, но блок может быть следующим:

    CASE WHEN gpa >= 3.3 THEN 'A'
         WHEN gpa > 2.7 AND gpa < 3.3 THEN 'B'
         WHEN gpa > 0 THEN 'C'
         ELSE 'F' END
    

Извините, я не знаю, как назначаются оценки за GPA, пожалуйста, отрегулируйте соответственно.

результирующий запрос для представления может быть (также на среда SQL Скрипка):

SELECT name,major,gpa,
       to_char(gpa, 'FM09.0') AS gpa_txt,
       name||'-'||major||'-Grade'||
  CASE WHEN gpa >= 3.3 THEN 'A'
       WHEN gpa > 2.7 AND gpa < 3.3 THEN 'B'
       WHEN gpa > 0 THEN 'C'
       ELSE 'F' END || '-' || to_char(gpa, 'FM09.0') AS adesc
  FROM atab;

чтобы построить представление, просто добавьте CREATE VIEW aview AS перед этим запросом.


редактировать

если вы все еще идете для добавления столбцов, следующее должно сделать трюк:

ALTER TABLE atab ADD gpa_txt text, ADD adesc text;
UPDATE atab SET
    gpa_txt = to_char(gpa, 'FM09.0'),
    adesc = name||'-'||major||'-Grade'||
      CASE WHEN gpa >= 3.3 THEN 'A'
           WHEN gpa > 2.7 AND gpa < 3.3 THEN 'B'
           WHEN gpa > 0 THEN 'C'
           ELSE 'F' END || '-' || to_char(gpa, 'FM09.0');

Я рекомендую" сгенерированный " столбец, а не хранить данные избыточно. Это займет меньше места на диске, что, скорее всего, сделает его быстрее, чем сохранение сгенерированного значения, и, безусловно, будет менее подвержено случайному выпадению из синхронизации с базовыми данными. Предполагая, что вам нравится формат, предоставленный @vyegorov, вы можете создать такую функцию, используя тип записи вашей таблицы (который соответствует имени таблицы) в качестве входных данных:

CREATE FUNCTION adesc(rec atab)
  RETURNS text
  IMMUTABLE
  LANGUAGE SQL
AS $$
SELECT to_char(.gpa, 'FM09.0') AS gpa_txt,
       .name||'-'||.major||'-Grade'||
  CASE WHEN .gpa >= 3.3 THEN 'A'
       WHEN .gpa > 2.7 AND .gpa < 3.3 THEN 'B'
       WHEN .gpa > 0 THEN 'C'
       ELSE 'F' END || '-' || to_char(.gpa, 'FM09.0') AS adesc;
$$;

вам нужно будет ссылка на это с помощью квалификатора отношения (имя таблицы или псевдоним). Если такая ссылка не разрешена путем поиска фактического столбца, PostgreSQL будет искать функцию, принимающую тип записи таблицы в качестве единственного параметра. Таким образом, Вы сможете сделать что-то вроде этого:

SELECT name, major, gpa, atab.adesc
  FROM atab;

такой "сгенерированный столбец" можно использовать в индексах для быстрого поиска, если это то, что вам нужно, с чем-то вроде adesc(atab).*.


вот запрос, который возвращает значения из таблицы с 3 столбцами:

select *
, to_char(gpa, '09.9') as gpa_text
, name || '-' || major || '-Grade' ||
case    when gpa between 3.5 and 4.0 then 'A'
    when gpa between 2.5 and 3.4 then 'B'
    when gpa between 1.5 and 2.4 then 'C'
    when gpa between 0.5 and 1.4 then 'D'
    else 'F' end
|| '-' || ltrim(to_char(gpa, '09.9')) as newfield
from students

это рабочий код, вот новое поле для Боба, "Боб-sci-GradeC-02.0"

Я настоятельно рекомендую, чтобы у вас не было текстового столбца в базе данных для хранения дубликата числового значения. Я не совсем уверен, зачем мне нужен ltrim, кажется странным, что форматированная строка будет иметь ведущий пробел.