Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Função com valor de tabela - Order by é ignorado na saída


Havia duas coisas erradas com sua abordagem original.
  1. Ao inserir na tabela, nunca foi garantido que o ORDER BY no INSERT ... SELECT ... ORDER BY seria a ordem em que as linhas foram realmente inseridas.
  2. Ao selecionar a partir dele, o SQL Server não garante que SELECT sem um ORDER BY retornará as linhas em qualquer ordem específica, como ordem de inserção.

Em 2012, parece que o comportamento mudou em relação ao item 1. Agora geralmente ignora o ORDER BY no SELECT declaração que é a fonte para um INSERT
DECLARE @T TABLE(number int)

INSERT INTO @T 
SELECT number
FROM master..spt_values
ORDER BY name

Plano 2008



Plano 2012




O motivo da mudança de comportamento é que nas versões anteriores o SQL Server produzia um plano que era compartilhado entre as execuções com SET ROWCOUNT 0 (desligado) e SET ROWCOUNT N . O operador de classificação estava lá apenas para garantir a semântica correta caso o plano fosse executado por uma sessão com um ROWCOUNT diferente de zero definir. O TOP operador à esquerda dele é um ROWCOUNT TOP .

O SQL Server 2012 agora produz planos separados para os dois casos, portanto, não há necessidade de adicioná-los ao ROWCOUNT 0 versão do plano.

Uma classificação ainda pode aparecer no plano em 2012 se o SELECT tem um TOP explícito definido (diferente de TOP 100 PERCENT ), mas isso ainda não garante a ordem de inserção real das linhas, o plano pode ter outra classificação após o TOP N é estabelecido para obter as linhas em ordem de índice clusterizado, por exemplo.

Para o exemplo em sua pergunta, eu apenas ajustaria o código de chamada para especificar ORDER BY name se é isso que requer.

Em relação ao seu sort_id ideia de Garantias de pedidos no SQL Server é garantido ao inserir em uma tabela com IDENTITY que a ordem em que eles são alocados será de acordo com o ORDER BY então você também pode fazer
DECLARE @Customer TABLE (
  Sort_Id     INT IDENTITY PRIMARY KEY,
  Customer_ID INT,
  Name        INT,
  Expired     BIT )

INSERT INTO @Customer
SELECT Customer_ID,
       Name,
       CASE
         WHEN Expiry_Date < Getdate() THEN 1
         WHEN Expired = 1 THEN 1
         ELSE 0
       END
FROM   Customer
ORDER  BY Name 

mas você ainda precisaria fazer o pedido pelo sort_id em suas consultas de seleção, pois não há pedidos garantidos sem isso (talvez este sort_id abordagem pode ser útil no caso em que as colunas originais usadas para ordenação não estão sendo copiadas para a variável da tabela)