PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

PostgreSQL Кръстосана заявка

Инсталирайте допълнителния модул tablefunc веднъж на база данни, която предоставя функцията crosstab() . От Postgres 9.1 можете да използвате CREATE EXTENSION за това:

CREATE EXTENSION IF NOT EXISTS tablefunc;

Подобрен тестов случай

CREATE TABLE tbl (
   section   text
 , status    text
 , ct        integer  -- "count" is a reserved word in standard SQL
);

INSERT INTO tbl VALUES 
  ('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
                    , ('C', 'Inactive', 7);  -- ('C', 'Active') is missing

Прост формуляр – не е подходящ за липсващи атрибути

crosstab(text) с1 входен параметър:

SELECT *
FROM   crosstab(
   'SELECT section, status, ct
    FROM   tbl
    ORDER  BY 1,2'  -- needs to be "ORDER BY 1,2" here
   ) AS ct ("Section" text, "Active" int, "Inactive" int);

Връща:

 Section | Active | Inactive
---------+--------+----------
 A       |      1 |        2
 B       |      4 |        5
 C       |      7 |           -- !!
  • Няма нужда от прехвърляне и преименуване.
  • Обърнете внимание на неправилното резултат за C :стойността 7 се попълва за първата колона. Понякога това поведение е желателно, но не и за този случай на употреба.
  • Опростената форма също е ограничена до точно три колони в предоставената входна заявка:име_на_ред , категория , стойност . Няма място за допълнителни колони като в алтернативата с 2 параметъра по-долу.

Безопасен формуляр

crosstab(text, text) с2 входни параметри:

SELECT *
FROM   crosstab(
   'SELECT section, status, ct
    FROM   tbl
    ORDER  BY 1,2'  -- could also just be "ORDER BY 1" here

  , $$VALUES ('Active'::text), ('Inactive')$$
   ) AS ct ("Section" text, "Active" int, "Inactive" int);

Връща:

 Section | Active | Inactive
---------+--------+----------
 A       |      1 |        2
 B       |      4 |        5
 C       |        |        7  -- !!
  • Обърнете внимание на правилния резултат за C .

  • Вторият параметър може да бъде всяка заявка, която връща един ред на атрибут, съответстващ на реда на дефиницията на колоната в края. Често ще искате да потърсите различни атрибути от основната таблица по следния начин:

      'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
    

Това е в ръководството.

Тъй като така или иначе трябва да посочите всички колони в списъка с дефиниции на колони (с изключение на предварително дефинирания crosstabN() варианти), обикновено е по-ефективно да предоставите кратък списък в VALUES израз, както е показано:

    $$VALUES ('Active'::text), ('Inactive')$$)

Или (не е в ръководството):

    $$SELECT unnest('{Active,Inactive}'::text[])$$  -- short syntax for long lists
  • Използвах доларово котиране за улесняване на цитирането.

  • Можете дори да извеждате колони сразлични типове данни с crosstab(text, text) - стига текстовото представяне на колоната за стойност е валидно въвеждане за целевия тип. По този начин може да имате атрибути от различен вид и да извеждате text , date , numeric и др. за съответните атрибути. В края на главата има пример за код crosstab(text, text) в ръководството.

db<>цигулка тук

Ефект от излишните входни редове

Излишните редове за въвеждане се обработват по различен начин – дублиращи се редове за една и съща комбинация („име_на_на“, „категория“) – (section, status) в горния пример.

1-параметър формуляр попълва налични колони за стойности отляво надясно. Излишните стойности се отхвърлят.
По-ранните редове за въвеждане печелят.

2-параметърът Формата присвоява всяка входна стойност на специалната й колона, като презаписва всяко предишно присвояване.
По-късно въведените редове печелят.

Обикновено нямате дубликати за начало. Но ако го направите, внимателно коригирайте реда на сортиране към вашите изисквания - и документирайте какво се случва.
Или получете бързи произволни резултати, ако не ви пука. Просто имайте предвид ефекта.

Разширени примери

  • Завъртане върху множество колони с помощта на Tablefunc – също така демонстрира споменатите „допълнителни колони“

  • Динамична алтернатива на завъртане с CASE и GROUP BY


\crosstabview в psql

Postgres 9.6 добави тази мета-команда към своя интерактивен терминал по подразбиране psql. Можете да изпълните заявката, която бихте използвали като първа crosstab() параметър и го подайте към \crosstabview (веднага или в следващата стъпка). Като:

db=> SELECT section, status, ct FROM tbl \crosstabview

Резултатът е подобен като по-горе, но това е функция за представяне от страна на клиента единствено и само. Входните редове се третират малко по-различно, следователно ORDER BY не се изисква. Подробности за \crosstabview в ръководството. Има още примери за код в долната част на тази страница.

Свързан отговор на dba.SE от Daniel Vérité (авторът на функцията psql):

  • Как да генерирам завъртано CROSS JOIN, където получената дефиниция на таблицата е неизвестна?


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да сравним датите в полетата за дата и час в Postgresql?

  2. Typecast низ към цяло число

  3. Изберете Номер на ред в postgres

  4. Postgresql json подобна заявка

  5. Как да приложим приоритети в SQL (postgres)