AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / 问题

Perguntas[cte](dba)

Martin Hope
seevans38
Asked: 2023-12-13 16:26:47 +0800 CST

Retornar a sequência consecutiva mais longa de um valor em uma coluna específica

  • 5

Estou usando o PostgreSQL 12.0 e tentando obter a sequência mais longa de linhas contínuas para uma coluna e valor específicos.

A tabela é chamada team2 e contém os resultados de uma equipe que se parece com:

match_id (pk), team_name (varchar), opposition (varchar), match_result (varchar)

Minha consulta está tentando encontrar a sequência mais longa de 'Win' em match_result. Há 23 vitórias no total e usando o olho a sequência mais longa deve retornar 5. No entanto, 23 são retornados. Como posso alterar minha consulta para selecionar apenas a sequência mais longa?

WITH ConsecutiveSequences AS (
  SELECT
    match_result,
    ROW_NUMBER() OVER () - ROW_NUMBER() OVER (ORDER BY match_id) AS grp
  FROM team2
  WHERE match_result = 'Win'
),
GroupedSequences AS (
  SELECT
    match_result,
    COUNT(*) AS consecutive_count
  FROM ConsecutiveSequences
  GROUP BY match_result, grp
)
SELECT
  COALESCE(MAX(consecutive_count), 0) AS longest_consecutive_sequence
FROM GroupedSequences;
cte
  • 1 respostas
  • 25 Views
Martin Hope
Biller Builder
Asked: 2022-09-20 09:02:15 +0800 CST

Como executar multi-inserções fictícias com generate_series ()?

  • 1

Dadas as tabelas assim: https://dbfiddle.uk/Z8hOhnYG

CREATE TABLE accounts (
  id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
);

CREATE TABLE profiles (
  id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY
);

CREATE TABLE account_profiles (
  id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  account_id bigint NOT NULL REFERENCES accounts,
  profile_id bigint NOT NULL REFERENCES profiles
);

Os requisitos são:

  • cada conta deve sempre ter pelo menos um perfil vinculado a ela.
  • portanto, uma nova conta deve sempre criar um novo perfil e adicionar sua linha de relação ao banco de dados
  • nada é criado quando toda a operação falha por qualquer motivo.

Portanto, para fins de lote, gostaria de escrevê-lo como uma consulta de várias inserções e criei este algoritmo:

  1. crie uma série de IDs com o mesmo comprimento que o número de contas
  2. adicionar contas
  3. juntar novas contas com a série
  4. adicionar perfis
  5. juntar novos perfis com a série
  6. junte as tabelas de séries de conta e perfil em seu id de série e insira o resultado na tabela de relações
  7. devolver novas contas
postgresql cte
  • 1 respostas
  • 43 Views
Martin Hope
hap76
Asked: 2022-06-18 09:01:16 +0800 CST

Procurando uma alternativa para um CTE que funcione como uma subconsulta em IF EXISTS

  • 1

Eu tenho um 'upsert' IF EXISTS funcionando bem sozinho em seu próprio proc armazenado. Mas quando tento usar a mesma instrução referenciando um CTE, ele não reconhece o CTE. Vejo no post relacionado que não tenho permissão para usar o CTE como a subconsulta. Estou curioso por que é isso, e de que outra forma eu poderia fazer isso?

Trabalhando o procedimento armazenado usando IF EXISTS:

ALTER Procedure [dbo].[sproc_receive]
    @StockCode VARCHAR(50), 
    @Qty DECIMAL(18,6)
AS

--source: https://weblogs.sqlteam.com/dang/2007/10/28/conditional-insertupdate-race-condition/

SET NOCOUNT, XACT_ABORT ON

BEGIN TRAN

IF EXISTS(SELECT * FROM tblReceivedQty WITH (UPDLOCK, HOLDLOCK) WHERE StockCode = @StockCode)
    BEGIN
          UPDATE tblReceivedQty
          SET ReceivedQty = ReceivedQty + @Qty
          WHERE StockCode = @StockCode
    END
ELSE
    BEGIN
          INSERT INTO tblReceivedQty (StockCode, ReceivedQty)
          VALUES (@StockCode, @Qty)
    END
COMMIT

RETURN @@ERROR
GO

E aqui está minha tentativa de redirecionar o IF EXISTS em outro proc armazenado que recebe uma string json como entrada.

USE [<databasename>]
GO

/****** Object:  StoredProcedure [dbo].[sproc_PutAway]    Script Date: 6/13/2022 4:14:02 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

ALTER Procedure [dbo].[sproc_PutAway]
(@json NVARCHAR(MAX) = '')
AS
BEGIN

-- Create CTE from JSON input
WITH json_received(StockCode, Qty)
AS
(
SELECT StockCode, Qty
    FROM OPENJSON(@json)
    WITH (
        StockCode VARCHAR(30) '$.StockCode',
        Qty DECIMAL(18,6) '$.Qty'
        )
)

SET NOCOUNT, XACT_ABORT ON

BEGIN TRAN

IF EXISTS(SELECT * FROM tblReceivedQty WITH (UPDLOCK, HOLDLOCK) WHERE tblReceivedQty.StockCode = json_received.StockCode)
    BEGIN
        UPDATE tblReceivedQty
        SET tblReceivedQty.ReceivedQty = tblReceivedQty.ReceivedQty - (
            SELECT Sum(Qty)
            FROM json_received
            WHERE tblReceivedQty.StockCode = json_received.StockCode
            GROUP BY json_received.StockCode
            )
    END
ELSE
    BEGIN
        INSERT INTO tblReceivedQty (StockCode, ReceivedQty)
        VALUES (json_received.StockCode, (-1 * json_received.Qty))
    END

COMMIT

RETURN @@ERROR
GO

Isso me dá um erro de sintaxe após o CTE e um 'identificador de várias partes não pôde ser vinculado' em todas as referências ao CTE.

Aprecie todas as dicas!

cte upsert
  • 1 respostas
  • 60 Views
Martin Hope
Matthew Moisen
Asked: 2022-02-24 19:56:19 +0800 CST

Atualização recursiva postgresql resultando em varredura sequencial

  • 2

Eu tenho uma tabela com uma chave estrangeira auto-referencial e gostaria de atualizar um determinado pai e todos os descendentes do pai com a mesma atualização recursiva.

Ao usar um UPDATE com uma CTE recursiva que retorna apenas 10 linhas de 25.000 linhas, o otimizador usa uma semijunção de hash com varredura sequencial na tabela que está sendo atualizada, em vez do loop aninhado mais otimizado e varredura de índice. Tem um tempo de execução lento de cerca de 5-10ms.

Aumentar o tamanho dessa tabela para 250 mil linhas levará ao uso da verificação de índice. Ironicamente, o tempo de execução é realmente muito mais rápido (~0,5 a 1,0ms), por uma ordem de grandeza, comparado a uma tabela de 25K (~5-10ms segundos), precisamente porque está usando o índice em vez de varredura sequencial.

Meu palpite aqui é que o otimizador é incapaz de executar primeiro o CTE e depois planejar a atualização, em vez disso, ele precisa planejar com antecedência e está assumindo incorretamente que o CTE está retornando um número muito maior de linhas do que realmente é.

O Postgres não permite dicas do otimizador de índice. Além de definir enable_seqscan como desativado na produção, existe alguma solução alternativa para que o postgres use o índice?


Configurar:

drop table emp;

create table emp (id int primary key, manager_id int, department text);
create index emp_manager_id on emp (manager_id);

insert into emp 
select i id, 
    case when mod(i, 10) = 0 then null else i - 1 end manager_id, 
    null department
from generate_series(0, 25000) as i;

analyze emp;
vacuum emp;

Aqui está a atualização DML. Isso atualiza apenas 10 linhas. Não importa se eu uso IN, EXISTS ou atualização do CTE recursivo, todos eles resultam em uma varredura sequencial

explain 
with recursive foo as (
    select id, manager_id, department
    from emp
    where id = 1000

    union all

    select emp.id, emp.manager_id, emp.department
    from emp join foo on emp.manager_id = foo.id
)
update emp
set department = 'IT'
where id in (select id from foo);

Resulta em

                                             QUERY PLAN
-----------------------------------------------------------------------------------------------------
 Update on emp  (cost=766.85..939.24 rows=101 width=74)
   CTE foo
     ->  Recursive Union  (cost=0.29..763.57 rows=101 width=40)
           ->  Index Scan using emp_pkey on emp emp_1  (cost=0.29..8.30 rows=1 width=40)
                 Index Cond: (id = 1000)
           ->  Nested Loop  (cost=0.29..75.32 rows=10 width=40)
                 ->  WorkTable Scan on foo foo_1  (cost=0.00..0.20 rows=10 width=4)
                 ->  Index Scan using emp_manager_id on emp emp_2  (cost=0.29..7.50 rows=1 width=40)
                       Index Cond: (manager_id = foo_1.id)
   ->  Hash Semi Join  (cost=3.28..175.67 rows=101 width=74)
         Hash Cond: (emp.id = foo.id)
         ->  Seq Scan on emp  (cost=0.00..145.01 rows=10001 width=14)
         ->  Hash  (cost=2.02..2.02 rows=101 width=32)
               ->  CTE Scan on foo  (cost=0.00..2.02 rows=101 width=32)

Explicar analisar dá o mesmo resultado. Estou usando explicar aqui por brevidade.


Essa semijunção de hash com varredura sequencial não é ideal, pois apenas 10 linhas de 25.000 estão sendo atualizadas. Um loop aninhado com uma varredura de índice seria ideal aqui.

Definir enable_seqscan=off reduz o tempo para ~0,1ms (de ~5-10ms)

Se eu não usar uma CTE recursiva, a seguinte atualização using generate_seriesmostra que o índice emp_id é usado corretamente para realizar a atualização por meio de um loop aninhado. Isso é o que eu esperaria da atualização recursiva do CTE.

explain 
update emp 
set department = 'IT' 
where id in (
    select i from generate_series(1000,1009) i
);


                                        QUERY PLAN
------------------------------------------------------------------------------------------
 Update on emp  (cost=0.43..83.59 rows=11 width=74)
   ->  Nested Loop  (cost=0.43..83.59 rows=11 width=74)
         ->  HashAggregate  (cost=0.14..0.25 rows=11 width=32)
               Group Key: i.i
               ->  Function Scan on generate_series i  (cost=0.00..0.11 rows=11 width=32)
         ->  Index Scan using emp_pkey on emp  (cost=0.29..7.58 rows=1 width=14)
               Index Cond: (id = i.i)

Se eu aumentar o número de linhas na tabela para 250K de 10K, o plano de explicação resultará no uso ideal do índice. No entanto, com varredura de 25.000 linhas/seq, leva ~5-10ms para executar. Com 250 mil linhas, a verificação do índice leva ~ 0,5-0,1 ms.

Meu palpite aqui é que o postgres não é capaz de executar primeiro o CTE e depois calcular um plano para a atualização. Ele precisa calcular um plano antes de executar o CTE. Portanto, o postgres não pode saber que apenas 10 linhas estão sendo retornadas do CTE e, em vez disso, precisa adivinhar o número. Portanto, o postgres está supondo que o CTE retornará algo como 1000 linhas, o que faz com que ele prefira a varredura sequencial quando a tabela contém apenas 25K. A razão pela qual minha tabela de 250K usa a varredura de índice, suponho, é que o postgres continua a adivinhar que o CTE está retornando 1000 linhas, mas de 250K uma varredura de índice faz mais sentido.


O Postgres não permite dicas do otimizador de índice. Além de definir enable_seqscan como desativado na produção, existe alguma solução alternativa para que o postgres use o índice?


A solução de @a_horse_with_no_name usando emp.id = any(array(select id from foo))é ótima. Isso resulta na seguinte explicação simples, que é um pouco diferente:

                                     QUERY PLAN
------------------------------------------------------------------------------------
 Update on emp  (cost=44.19..48.93 rows=10 width=46)
   CTE foo
     ->  Recursive Union  (cost=0.00..42.17 rows=101 width=11)
           ->  Seq Scan on emp emp_1  (cost=0.00..3.08 rows=1 width=11)
                 Filter: (id = 0)
           ->  Hash Join  (cost=0.33..3.71 rows=10 width=11)
                 Hash Cond: (emp_2.manager_id = foo.id)
                 ->  Seq Scan on emp emp_2  (cost=0.00..2.66 rows=166 width=11)
                 ->  Hash  (cost=0.20..0.20 rows=10 width=4)
                       ->  WorkTable Scan on foo  (cost=0.00..0.20 rows=10 width=4)
   InitPlan 2 (returns $2)
     ->  CTE Scan on foo foo_1  (cost=0.00..2.02 rows=101 width=4)
   ->  Seq Scan on emp  (cost=0.00..4.73 rows=10 width=46)
         Filter: (id = ANY ($2))

Alguém pode explicar a diferença entre essas duas partes:

Original com enable_seqscan=off:

   ->  Nested Loop  (cost=2.56..294.11 rows=101 width=74) (actual time=0.091..0.118 rows=10 loops=1)
         ->  HashAggregate  (cost=2.27..3.28 rows=101 width=32) (actual time=0.076..0.080 rows=10 loops=1)
               Group Key: foo.id
               Batches: 1  Memory Usage: 24kB
               ->  CTE Scan on foo  (cost=0.00..2.02 rows=101 width=32) (actual time=0.024..0.068 rows=10 loops=1)
         ->  Index Scan using emp_pkey on emp  (cost=0.29..2.88 rows=1 width=14) (actual time=0.003..0.003 rows=1 loops=10)
               Index Cond: (id = foo.id)

Usando any(array(...)):

   InitPlan 2 (returns $2)
     ->  CTE Scan on foo foo_1  (cost=0.00..2.02 rows=101 width=4)
   ->  Seq Scan on emp  (cost=0.00..4.73 rows=10 width=46)
         Filter: (id = ANY ($2))

Primeiro, minha consulta original resulta em um HashAggregate do cte recursivo foo.iddepois de executar a varredura CTE. Somente depois disso ele percorre o empíndice. Não entendo porque está fazendo isso. Usando any(array(...)), ele pulará esta etapa e simplesmente fará um loop aninhado sobre a varredura cte e a varredura de índice.

Segundo, e provavelmente o mais importante, usar any(array(...))resultados neste arquivo InitPlan 2. Acredito que o que está acontecendo aqui é que de any(array(...))alguma forma força o planejador de consultas a executá-las como duas consultas diferentes. Primeiro ele executa o CTE, que retorna apenas 10 linhas. Então, o planejador sabe que com apenas 10 linhas ele pode usar uma varredura de índice em vez de seqscan. Minha solução original, por algum motivo, não pode forçar o planejador de consultas a executá-las como duas consultas diferentes, portanto, o planejador de consultas não sabe de antemão quantas linhas estão sendo retornadas.

Alguma ideia?

postgresql cte
  • 1 respostas
  • 186 Views
Martin Hope
Jurgen Cuschieri
Asked: 2022-01-09 07:20:05 +0800 CST

CTE recursivo no PostgreSQL para gerar dados com diferentes frequências

  • 2

Estou tentando escrever uma consulta de geração de dados que usa CTE recursiva no Postgresql 14.

Considere o esquema "sc" que inclui uma função getfreq. getfreq recebe um int como parâmetro (que representa uma chave estrangeira para outra tabela) e retorna um int back, que representa uma frequência.

Agora considere esta consulta:

WITH RECURSIVE rec AS 
(
SELECT 1 as fk FROM generate_series(1, sc.getfreq(1), 1)
UNION ALL
SELECT r.fk + 1 FROM rec AS r WHERE r.fk + 1 <= 10
)
select row_number() OVER () as pk, fk from rec

getfreq espera um int de 1 a 10 (daí a condição de saída r.fk <= 10). Ele retorna uma frequência N. Eu quero que cada iteração do CTE recursivo crie N linhas. O resultado de cada iteração deve ser combinado pela cláusula UNION ALL. No final, quero um resultado em que a contagem de linhas seja igual à soma das frequências retornadas por getfreq nas 10 iterações.

No exemplo acima, sc.getfreq(1) sempre retornará 5, portanto, estou obtendo um conjunto de resultados de 50 linhas; primeiros 5 com fk = 1, segundos 5 com fk = 2 e assim por diante. No entanto, sc.getfreq() deve de fato ser chamado com o valor iterado, então a segunda iteração deve ser sc.getfreq(2) e assim por diante. Naturalmente, sc.getfreq(2) retornaria uma frequência diferente e não 5 e, portanto, o resultado final não deveria ter 50 linhas.

Eu tentei usar "fk" em getfreq, da seguinte forma: sc.getfreq(fk); já que "fk" está sendo incrementado pela parte recursiva do CTE (e, portanto, seria 2 na segunda iteração, 3 na terceira iteração e assim por diante), mas a coluna "fk" não existe dentro do contexto do FROM, presumivelmente porque a parte "SELECT" ainda não teria sido executada.

Os CTEs recursivos são adequados para resolver isso? Posso conseguir com o que quero com alguns ajustes?

Exemplo de saída onde getfreq(1) retorna 5, getfreq(2) retorna 2 e getfreq(3) retorna 1.

PK FK
1 1
2 1
3 1
4 1
5 1
6 2
7 2
8 3

...... e assim por diante (este é um exemplo incompleto de 3 iterações).

postgresql cte
  • 1 respostas
  • 172 Views
Martin Hope
Doug Coats
Asked: 2021-06-16 10:18:53 +0800 CST

CTEs aninhados que retornam resultados incorretos em determinadas situações

  • 8

OK, primeiro deixe-me dizer que recebi esse problema de:

  • Buscando explicação de junção errada do Tsql no CTE [fechado]

Eu estava tentando ajudar a descobrir o problema, mas fiquei perplexo ao tentar depurar o código uma etapa de cada vez. Eu sei que o problema é devido aos CTEs aninhados (porque durante a depuração, se você despejar cada etapa aka cteX em tabelas temporárias, os resultados corretos são alcançados), mas não sabendo como eles funcionam "sob o capô", não posso explicá-lo de maneira sensata fora de "não funciona yo." Eu suspeito que tenha algo a ver com a forma como o compilador está tentando avaliá-los todos ao mesmo tempo durante o tempo de execução, mas sem mais contexto não posso dizer com certeza.

Minha pergunta é apenas tentar entender como eles funcionam sob o capô e como isso se relaciona com essa situação. Agora que estou envolvido, só quero entender o assunto para poder falar sobre ele no futuro e aprender algo divertido nesse meio tempo.

Quem responder aqui também pode fazer cross post no SO e responder lá também.

Configuração do código:

declare @t1 TABLE (ID varchar(max),Action varchar(max), DateTime datetime );
INSERT INTO @t1
Select *
from
(
VALUES 
('w2337','Open','2020-11-06 12:28:10.000'),
('w2337','Hold','2021-06-14 14:50:59.000'),
('w2337','Open','2021-06-14 14:51:26.000'),
('w2337','Hold','2021-06-15 14:50:59.000'),
('w2337','Open','2021-06-17 14:51:26.000'),
('w2337','Open','2021-06-18 14:51:26.000')

) t (ID, Action, DateTime);

with cte1 as (
select [ID],[Action],[DateTime]
,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) as [RegIndex]
,DENSE_RANK () OVER (ORDER BY ID) as [Index by ID]
,ROW_NUMBER() OVER (PARTITION BY ID ORDER BY [DateTime]) as [Index by DateTimeID]
,CASE when [Action]='Hold' then ROW_NUMBER() OVER (PARTITION BY ID,Action ORDER BY DateTime) end as [TimesHeld]
FROM @t1 
)
,cte2 as (
select *, MAX([TimesHeld]) OVER (PARTITION BY ID ORDER BY RegIndex ROWS UNBOUNDED PRECEDING) as [FD] from cte1 
)
,cte3 as(
select *, CASE when [Action]='Open' then ROW_NUMBER() OVER (PARTITION BY ID,Action ORDER BY DateTime) end as [TimesOpened]
from cte2 
where FD is not null
)
select 
    a.*, ' ' as thing, b.DateTime  -- b.*   alternating between the direct column versus all is the issue
from cte3 a 
LEFT OUTER JOIN cte3 b
ON a.ID=b.ID and a.TimesHeld=b.TimesOpened 
where a.TimesHeld is not null and b.TimesOpened is not null

Detalhes:

Ao compilar as consultas abaixo, no LEFT OUTER JOIN final, se você selecionar b.* obterá os resultados corretos. No entanto, se você selecionar apenas uma coluna (datetime, por exemplo), os resultados não estarão corretos.

Correto:

insira a descrição da imagem aqui

Incorreta:

insira a descrição da imagem aqui

sql-server cte
  • 2 respostas
  • 1083 Views
Martin Hope
PakLui
Asked: 2021-06-01 09:47:40 +0800 CST

Eu gostaria, por meio de CTEs recursivos, uma consulta para retornar todos os carros em forma de árvore, mas classificados em cada categoria

  • 3

Aqui está a tabela e os dados para teste:

CREATE TABLE if not exists cars (
    id serial PRIMARY KEY, 
    parent_code INT,
    descr CHARACTER VARYING(50) NOT NULL
);

-- Level 1
INSERT INTO cars(parent_code, descr) VALUES (null, 'Volkswagen');
INSERT INTO cars(parent_code, descr) VALUES (null, 'Tesla');

-- Level 2
INSERT INTO cars(parent_code, descr) VALUES (1, 'Polo');
INSERT INTO cars(parent_code, descr) VALUES (1, 'Golf');

INSERT INTO cars(parent_code, descr) VALUES (2, '3');
INSERT INTO cars(parent_code, descr) VALUES (2, 'S');
INSERT INTO cars(parent_code, descr) VALUES (2, 'X');

-- Level 3
INSERT INTO cars(parent_code, descr) VALUES (3, 'diesel');
INSERT INTO cars(parent_code, descr) VALUES (3, 'gasoline');

INSERT INTO cars(parent_code, descr) VALUES (4, 'diesel');
INSERT INTO cars(parent_code, descr) VALUES (4, 'gasoline');

INSERT INTO cars(parent_code, descr) VALUES (5, 'electric');
INSERT INTO cars(parent_code, descr) VALUES (6, 'electric');
INSERT INTO cars(parent_code, descr) VALUES (7, 'electric');

E aqui está a visão (que eu tentei) com um CTE recursivo:

WITH RECURSIVE tree_cars AS (
  select descr
  from cars
  union all

  select concat('  -> ', descr)
  from cars
)
--table tree_cars;
select * from tree_cars;

Mas a saída não é o que eu esperava:

Volkswagen
Tesla
Polo
Golf
3
S
X
diesel
gasoline
diesel
gasoline
electric
electric
electric
  -> Volkswagen
  -> Tesla
  -> Polo
  -> Golf
  -> 3
  -> S
  -> X
  -> diesel
  -> gasoline
  -> diesel
  -> gasoline
  -> electric
  -> electric
  -> electric

Já que eu gostaria de algo como:

Tesla
  -> 3
      -> electric
  -> S
      -> electric
  -> X
      -> electric
Volkswagen
  -> Golf
      -> diesel
      -> gasoline
  -> Polo
      -> diesel
      -> gasoline
postgresql cte
  • 1 respostas
  • 44 Views
Martin Hope
tucomax
Asked: 2021-05-31 11:00:48 +0800 CST

Como posso alterar a saída de string em uma árvore de hierarquia com o PostgreSQL?

  • 2

Tenho uma tabela assim:

-------------------------------------------------
|  id  | description         | parent_id   |  cost
--------------------------------------------------
| 1    |  Radiology         |       NULL  | 0.00
| 2    |  Lab Tests         |       NULL  | 0.00
| 3    |  Normal Radiology  |         1   | 0.00
| 4    |  Resonance         |         1   | 100.00
| 1100 |  Cerebral Resonance|         4   | 200.00
| 1900 |  Blood Tests       |         2   | 10.00
| 2044 |  Calcium           |         2   | 50.00

---------------------------------------------------

Eu preciso gerar esse tipo de saída:

Radiology
   -->Normal Radiology
   -->Resonance
      -->Cerebral Resonance with contrast
Lab Test
    --> Blood Test
    --> Calcium

Estou trabalhando no PostgreSQL. Eu tenho tentado isso com um CTE recursivo, mas não consegui gerar o que gosto:

WITH RECURSIVE hierarchy AS (
    SELECT  id, CAST(description AS TEXT) AS parent_list
    FROM    orders
    WHERE   parent_id is null
      UNION
    SELECT  c.id,
            CAST(c2.parent_list || ' --> ' || c.description as text) as parent_list
    FROM orders c
    INNER JOIN hierarchy c2 ON c.parent_id = c2.id )

SELECT  id, parent_list
FROM     hierarchy
GROUP BY id, parent_list
ORDER BY parent_list;

Esse CTE recursivo produz a seguinte saída indesejável:

Radiology
Radiology--> Normal Radiology
Radiology--> Resonance
Radiology--> Resonance --> Cerebral Resonance with contrast
Lab Test
Lab Test --> Blood Test
Lab Test --> Calcium

Como eu posso fazer isso?

postgresql cte
  • 1 respostas
  • 247 Views
Martin Hope
tucomax
Asked: 2021-05-29 23:59:11 +0800 CST

Como mesclar várias linhas em uma coluna com hierarquia Postgresql 12?

  • 1

Tenho uma tabela assim para salvar o catálogo de 90 serviços:

-------------------------------------------------------------------------------------
|  id  |  service     | subservice      | description                      | cost
-------------------------------------------------------------------------------------
| 2044 |   Tests      |   Tests         | Calcium                          | 50.00
| 1385 |   Cardiology |   Cardioversion | Electric Cardioversion programmed| 200.00
| 7000 |   Cardiology |  Ecocardiography| Chest Ultrasound                 | 100.00
-------------------------------------------------------------------------------------

Preciso alterar a estrutura da tabela para ter os três níveis (serviço, subserviço e descrição) na mesma coluna com id próprio e apontando para uma nova coluna com o número do nível. Ou seja, algo assim (observe que os id's são algo que eu inventei):

-------------------------------------------------------------------------------------
|  id  | description  | parent_id   |  cost
-------------------------------------------------------------------------------------
| 1    |   Tests      |       NULL  | 0.00
| 2    |   Tests      |         1   | 0.00
| 2044 |   Calcium    |         2   | 50.00
-------------------------------------------------------------------------------------

Estou trabalhando no Postgresql 12. Criei a nova coluna parent_id e estava tentando fazer esta sequência:

CREATE SEQUENCE seq_parent_id INCREMENT BY 1 START WITH 1 NO CYCLE;

ALTER TABLE catalog
ALTER COLUMN parent_id SET DEFAULT nextval('seq_parent_id')

Alguém pode por favor dar uma idéia aproximada de como transformar a estrutura da tabela?

postgresql cte
  • 1 respostas
  • 241 Views
Martin Hope
Oscar
Asked: 2021-02-27 02:17:49 +0800 CST

Manipulação de strings em CTE recursiva

  • 6

Estou tentando fazer algo como o seguinte trabalho:

WITH results(n, string ) AS (
            SELECT 1,'lol'
            UNION ALL
            SELECT n+1, string + ' lol'
            FROM results
            WHERE n<6
            )
            SELECT * FROM results

Mas o SQL parece não reconhecer a concatenação de strings na segunda coluna e retorna o erro:

Os tipos não correspondem entre a âncora e a parte recursiva na coluna "string" da consulta recursiva "resultados".

Minha saída desejada seria algo como

1, rs

2, lol lol

3, lol lol lol

e assim por diante

sql-server cte
  • 1 respostas
  • 930 Views

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve