Pergunta

Preciso recuperar todas as linhas de uma tabela onde 2 colunas combinadas são diferentes.Então eu quero todas as vendas que não tenham nenhuma outra venda que aconteceu no mesmo dia pelo mesmo preço.As vendas exclusivas com base no dia e no preço serão atualizadas para um status ativo.

Então estou pensando:

UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
             FROM sales
             HAVING count = 1)

Mas meu cérebro dói indo além disso.

Foi útil?

Solução

SELECT DISTINCT a,b,c FROM t

é aproximadamente equivalente a:

SELECT a,b,c FROM t GROUP BY a,b,c

É uma boa ideia se acostumar com a sintaxe GROUP BY, pois é mais poderosa.

Para sua consulta, eu faria assim:

UPDATE sales
SET status='ACTIVE'
WHERE id IN
(
    SELECT id
    FROM sales S
    INNER JOIN
    (
        SELECT saleprice, saledate
        FROM sales
        GROUP BY saleprice, saledate
        HAVING COUNT(*) = 1 
    ) T
    ON S.saleprice=T.saleprice AND s.saledate=T.saledate
 )

Outras dicas

Se você juntar as respostas até agora, limpar e melhorar, chegará a esta pergunta superior:

UPDATE sales
SET    status = 'ACTIVE'
WHERE  (saleprice, saledate) IN (
    SELECT saleprice, saledate
    FROM   sales
    GROUP  BY saleprice, saledate
    HAVING count(*) = 1 
    );

Qual é muito mais rápido do que qualquer um deles.Reduz o desempenho da resposta atualmente aceita por um fator de 10 a 15 (em meus testes no PostgreSQL 8.4 e 9.1).

Mas isto ainda está longe de ser o ideal.Use um NOT EXISTS (anti-)semi-junção para um desempenho ainda melhor. EXISTS é o SQL padrão, existe desde sempre (pelo menos desde o PostgreSQL 7.2, muito antes de esta pergunta ser feita) e atende perfeitamente aos requisitos apresentados:

UPDATE sales s
SET    status = 'ACTIVE'
WHERE  NOT EXISTS (
   SELECT FROM sales s1                     -- SELECT list can be empty for EXISTS
   WHERE  s.saleprice = s1.saleprice
   AND    s.saledate  = s1.saledate
   AND    s.id <> s1.id                     -- except for row itself
   )
AND    s.status IS DISTINCT FROM 'ACTIVE';  -- avoid empty updates. see below

banco de dados<> violino aqui
Velho violino SQL

Chave exclusiva para identificar linha

Se você não tiver uma chave primária ou exclusiva para a tabela (id no exemplo), você pode substituir pela coluna do sistema ctid para os fins desta consulta (mas não para outros fins):

   AND    s1.ctid <> s.ctid

Toda tabela deve ter uma chave primária.Adicione um se você ainda não tiver um.Eu sugiro um serial ou um IDENTITY coluna no Postgres 10+.

Relacionado:

Como isso é mais rápido?

A subconsulta no EXISTS anti-semi-join pode parar de avaliar assim que o primeiro idiota for encontrado (não adianta procurar mais).Para uma tabela base com poucas duplicatas, isso é apenas um pouco mais eficiente.Com muitas duplicatas isso se torna caminho mais eficiente.

Excluir atualizações vazias

Para linhas que já possuem status = 'ACTIVE' esta atualização não mudaria nada, mas ainda inseriria uma nova versão de linha com custo total (aplicam-se pequenas exceções).Normalmente, você não quer isso.Adicionar outro WHERE condição como demonstrada acima para evitar isso e torná-lo ainda mais rápido:

Se status é definido NOT NULL, você pode simplificar para:

AND status <> 'ACTIVE';

Diferença sutil no tratamento de NULL

Esta consulta (diferentemente da resposta atualmente aceita por Joel) não trata valores NULL como iguais.As duas linhas seguintes para (saleprice, saledate) seria qualificado como "distinto" (embora parecesse idêntico ao olho humano):

(123, NULL)
(123, NULL)

Também passa em um índice exclusivo e em quase qualquer outro lugar, já que os valores NULL não são comparados iguais de acordo com o padrão SQL.Ver:

OTOH, GROUP BY, DISTINCT ou DISTINCT ON () trate os valores NULL como iguais.Use um estilo de consulta apropriado dependendo do que você deseja alcançar.Você ainda pode usar esta consulta mais rápida com IS NOT DISTINCT FROM em vez de = para uma ou todas as comparações para tornar a comparação NULL igual.Mais:

Se todas as colunas que estão sendo comparadas estiverem definidas NOT NULL, não há espaço para divergências.

O problema com sua consulta é que, ao usar uma cláusula GROUP BY (o que você basicamente faz usando distinto), você só pode usar colunas agrupadas ou funções agregadas.Você não pode usar o ID da coluna porque existem valores potencialmente diferentes.No seu caso, sempre há apenas um valor por causa da cláusula HAVING, mas a maioria dos RDBMS não é inteligente o suficiente para reconhecer isso.

No entanto, isso deve funcionar (e não precisa de junção):

UPDATE sales
SET status='ACTIVE'
WHERE id IN (
  SELECT MIN(id) FROM sales
  GROUP BY saleprice, saledate
  HAVING COUNT(id) = 1
)

Você também pode usar MAX ou AVG em vez de MIN; só é importante usar uma função que retorne o valor da coluna se houver apenas uma linha correspondente.

Quero selecionar os valores distintos de uma coluna 'GrondOfLucht', mas eles devem ser classificados na ordem fornecida na coluna 'classificação'.Não consigo obter os valores distintos de apenas uma coluna usando

Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering

Também fornecerá a coluna 'classificação' e como 'GrondOfLucht' AND 'classificação' não é único, o resultado será TODAS as linhas.

use o GROUP para selecionar os registros de 'GrondOfLucht' na ordem dada por 'sortering

SELECT        GrondOfLucht
FROM            dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)

Se o seu DBMS não suporta distinção com múltiplas colunas como esta:

select distinct(col1, col2) from table

A seleção múltipla em geral pode ser executada com segurança da seguinte forma:

select distinct * from (select col1, col2 from table ) as x

Como isso pode funcionar na maioria dos DBMS e espera-se que seja mais rápido do que agrupar por solução, pois você evita a funcionalidade de agrupamento.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top