Dadas duas tabelas com uma contagem de linhas indefinidas com um nome e um valor, como eu exibiria CROSS JOIN
uma função dinâmica sobre seus valores.
CREATE TEMP TABLE foo AS
SELECT x::text AS name, x::int
FROM generate_series(1,10) AS t(x);
CREATE TEMP TABLE bar AS
SELECT x::text AS name, x::int
FROM generate_series(1,5) AS t(x);
Por exemplo, se essa função fosse multiplicação, como eu geraria uma tabela (multiplicação) como a abaixo,
Todas essas (arg1,arg2,result)
linhas podem ser geradas com
SELECT foo.name AS arg1, bar.name AS arg2, foo.x*bar.x AS result
FROM foo
CROSS JOIN bar;
Portanto, isso é apenas uma questão de apresentação. Gostaria que ele também trabalhasse com um nome personalizado - um nome que não é apenas o argumento CAST
editado no texto, mas definido na tabela,
CREATE TEMP TABLE foo AS
SELECT chr(x+64) AS name, x::int
FROM generate_series(1,10) AS t(x);
CREATE TEMP TABLE bar AS
SELECT chr(x+72) AS name, x::int
FROM generate_series(1,5) AS t(x);
Eu acho que isso seria facilmente possível com um CROSSTAB capaz de um tipo de retorno dinâmico.
SELECT * FROM crosstab(
'
SELECT foo.x AS arg1, bar.x AS arg2, foo.x*bar.x
FROM foo
CROSS JOIN bar
', 'SELECT DISTINCT name FROM bar'
) AS **MAGIC**
Mas, sem o **MAGIC**
, eu recebo
ERROR: a column definition list is required for functions returning "record" LINE 1: SELECT * FROM crosstab(
Para referência, usando os exemplos acima com nomes isso é algo mais parecido com o que tablefunc
's crosstab()
necessidades.
SELECT * FROM crosstab(
'
SELECT foo.x AS arg1, bar.x AS arg2, foo.x*bar.x
FROM foo
CROSS JOIN bar
'
) AS t(row int, i int, j int, k int, l int, m int);
Mas agora voltamos a fazer suposições sobre o conteúdo e o tamanho da bar
tabela em nosso exemplo. Então se,
- As tabelas são de comprimento indefinido,
- Em seguida, a junção cruzada representa um cubo de dimensão indefinida (por causa do acima),
- Os nomes de categorias (linguagem de tabulação cruzada) estão na tabela
Qual é o melhor que podemos fazer no PostgreSQL sem uma "lista de definições de colunas" para gerar esse tipo de apresentação?
fonte
Respostas:
Caso simples, SQL estático
A solução não dinâmica
crosstab()
para o caso simples:Eu ordeno as colunas resultantes por
foo.name
, nãofoo.x
. Os dois são classificados em paralelo, mas essa é apenas a configuração simples. Escolha a ordem de classificação correta para o seu caso. O valor real da segunda coluna é irrelevante nesta consulta (forma de 1 parâmetro decrosstab()
).Nem precisamos de
crosstab()
dois parâmetros porque não há valores ausentes por definição. Vejo:(Você corrigiu a consulta de tabela de referência cruzada na pergunta substituindo
foo
porbar
em uma edição posterior. Isso também corrige a consulta, mas continua trabalhando com nomes defoo
.)Tipo de retorno desconhecido, SQL dinâmico
Os nomes e tipos de colunas não podem ser dinâmicos. O SQL exige saber número, nomes e tipos de colunas resultantes no momento da chamada. Por declaração explícita ou por informações nos catálogos do sistema (é o que acontece com
SELECT * FROM tbl
: O Postgres consulta a definição da tabela registrada.)Você deseja que o Postgres obtenha colunas resultantes dos dados em uma tabela de usuário. Não vai acontecer.
De uma forma ou de outra, você precisa de duas viagens de ida e volta ao servidor. Ou você cria um cursor e depois o percorre. Ou você cria uma tabela temporária e seleciona nela. Ou você registra um tipo e o usa na chamada.
Ou você simplesmente gera a consulta em uma etapa e a executa na próxima:
Isso gera a consulta acima dinamicamente. Execute-o na próxima etapa.
Estou usando dollar-quote (
$$
) para manter o manuseio de aspas aninhadas simples. Vejo:quote_ident()
é essencial para evitar nomes de colunas ilegais (e possivelmente defender-se da injeção de SQL).Palavras-chave:
fonte
Se você enquadrar isso como um problema de apresentação, considere um recurso de apresentação pós-consulta.
As versões mais recentes do
psql
(9.6) são fornecidas\crosstabview
, mostrando um resultado na representação de tabela de referência cruzada sem suporte ao SQL (já que o SQL não pode produzi-lo diretamente, como mencionado na resposta de @ Erwin: SQL exige saber número, nomes e tipos de colunas resultantes no momento da chamada )Por exemplo, sua primeira consulta fornece:
O segundo exemplo com nomes de coluna ASCII fornece:
Veja o manual do psql e https://wiki.postgresql.org/wiki/Crosstabview para mais.
fonte
Esta não é uma solução definitiva
Esta é a minha melhor abordagem até agora. Ainda é necessário converter a matriz final em colunas.
Primeiro, eu tenho o produto cartesiano de ambas as tabelas:
Mas adicionei um número de linha apenas para identificar todas as linhas da primeira tabela.
Então eu comprei o resultado neste formato:
Convertendo-o em string delimitada por comas:
(Apenas para tentar mais tarde: http://rextester.com/NBCYXA2183 )
fonte
Como uma observação lateral, parece que o SQL: 2016 acomodará isso com as funções da tabela polimórfica (ISO / IEC TR 19075-7: 2017)
Encontrei o link What's New in SQL: 2016, mas o autor não expande muito.
fonte