SOMAR SOBRE A PARTIÇÃO POR

O que me está a escapar?

esta consulta está a devolver dados duplicados vezes sem conta. A contagem é correta para um total completo, mas eu estou esperando uma linha, e ainda estou recebendo o valor repetido cerca de 40 vezes. Alguma ideia?

SELECT BrandId
      ,SUM(ICount) OVER (PARTITION BY BrandId ) 
  FROM Table 
WHERE DateId  = 20130618
Já percebi?

BrandId ICount
2       421762
2       421762
2       421762
2       421762
2       421762
2       421762
2       421762
1       133346
1       133346
1       133346
1       133346
1       133346
1       133346
1       133346
O que me está a escapar?

não posso remover a partição porque toda a consulta é assim:

SELECT BrandId
       ,SUM(ICount) OVER (PARTITION BY BrandId) 
       ,TotalICount= SUM(ICount) OVER ()    
        ,SUM(ICount) OVER () / SUM(ICount) OVER (PARTITION BY BrandId)  as Percentage
FROM Table 
WHERE DateId  = 20130618

que devolve isto:

BrandId (No column name)    TotalICount Percentage
2       421762              32239892    76
2       421762              32239892    76
2       421762              32239892    76
2       421762              32239892    76
2       421762              32239892    76
2       421762              32239892    76
Eu esperaria uma saída como esta sem ... ter de utilizar um método distinto:

BrandId (No column name)    TotalICount Percentage
2       421762              32239892    76
9       1238442             32239892    26
10      1467473             32239892    21
Author: SAm, 2013-07-26

4 answers

Podias ter usado DISTINCT ou apenas remover as porções PARTITION BY e usar GROUP BY:

SELECT BrandId
       ,SUM(ICount)
       ,TotalICount = SUM(ICount) OVER ()    
       ,Percentage = SUM(ICount) OVER ()*1.0 / SUM(ICount) 
FROM Table 
WHERE DateId  = 20130618
GROUP BY BrandID

Não sei por que você está dividindo o total pela contagem por brand, se isso é um erro e você quer por cento do total, em seguida, reverter esses bits acima para:

SELECT BrandId
           ,SUM(ICount)
           ,TotalICount = SUM(ICount) OVER ()    
           ,Percentage = SUM(ICount)*1.0 / SUM(ICount) OVER () 
    FROM Table 
    WHERE DateId  = 20130618
    GROUP BY BrandID
 9
Author: Hart CO, 2013-07-25 20:27:53

Na minha opinião, acho que é importante explicar o por quepor trás da necessidade de um grupo no seu SQL ao somar com a cláusula sobre() e por que Você está recebendo linhas repetidas de dados quando você está esperando uma linha por brand.

Tome este exemplo: você precisa agregar o preço total de venda de cada linha de ordem, por categoria de ordem específica, entre duas datas, mas você também precisa manter os dados de ordem individual em seus resultados finais. Um montante() sobre o preço de venda a coluna não lhe permitiria obter os totais correctos porque exigiria um grupo, pelo que esmagaria os detalhes porque não seria capaz de manter as linhas de encomendas individuais na instrução select.

Muitas vezes vemos uma tabela #temp, variável @table, ou CTE preenchido com a soma de nossos dados e agrupados para que possamos juntar-nos a ele novamente mais tarde para obter uma coluna das somas que precisamos. Isto pode adicionar tempo de processamento e linhas extras de código. Em vez disso, use o OVER (partição por () como isto:

SELECT
  OrderLine, 
  OrderDateTime, 
  SalePrice, 
  OrderCategory,
  SUM(SalePrice) OVER(PARTITION BY OrderCategory) AS SaleTotalPerCategory
FROM tblSales 
WHERE OrderDateTime BETWEEN @StartDate AND @EndDate

Repare que não estamos a agrupar e temos a coluna de linhas de ordem individual seleccionada. A partição por na última coluna nos devolverá um total de preço de venda para cada linha de dados em cada categoria. O que a última coluna, essencialmente, diz que é, queremos que o soma do preço de venda (SOMA(SalePrice)) sobre um partição dos meus resultados e por especificado categoria (MAIS(PARTIÇÃO CategoryHere) .

Se removermos as outras colunas da nossa instrução seleccionada, e deixarmos a nossa coluna de soma final (), como esta:

SELECT
  SUM(SalePrice) OVER(PARTITION BY OrderCategory) AS SaleTotalPerCategory
FROM tblSales 
WHERE OrderDateTime BETWEEN @StartDate AND @EndDate

Os resultados continuarão a repetir esta soma para cada linha do nosso conjunto de resultados original. A razão é que este método não requer um grupo por. Se você não precisa reter dados de linha individuais, então simplesmente somar () sem o uso de OVER() e agrupar seus dados apropriadamente. Mais uma vez, se você precisar de uma coluna adicional com totais específicos, você pode usar o método OVER (partição por ()) descrito acima sem seleção adicional para se juntar de volta.

O acima é puramente para explicar por que ele está recebendo linhas repetidas do mesmo número e para ajudar a entender o que esta cláusula prevê. Este método pode ser usado de muitas maneiras e eu encorajo muito mais a leitura da documentação aqui:

Over Clause

 20
Author: E10, 2015-01-15 23:18:18

Remover partition by e adicionar group by Cláusula,

SELECT BrandId
      ,SUM(ICount) totalSum
  FROM Table 
WHERE DateId  = 20130618
GROUP BY BrandId
 6
Author: John Woo, 2013-07-25 20:11:10

Acho que a pergunta que queres é esta:

SELECT BrandId, SUM(ICount),
       SUM(sum(ICount)) over () as TotalCount,
       100.0 * SUM(ICount) / SUM(sum(Icount)) over () as Percentage
FROM Table 
WHERE DateId  = 20130618
group by BrandId;

Isto faz o group by para a marca. E calcula a "percentagem". Esta versão deve produzir um número entre 0 e 100.

 6
Author: Gordon Linoff, 2013-07-25 20:21:34