T-SQL - Qual é a maneira mais eficiente de percorrer uma tabela até que uma condição seja atendida

10

Em conseguiu uma tarefa de programação na área de T-SQL.

Tarefa:

  1. As pessoas querem entrar no elevador, cada pessoa tem um certo peso.
  2. A ordem das pessoas que estão na fila é determinada pelo giro da coluna.
  3. O elevador tem uma capacidade máxima de <= 1000 lbs.
  4. Retorne o nome da última pessoa que pode entrar no elevador antes que fique muito pesado!
  5. O tipo de retorno deve ser tabela

insira a descrição da imagem aqui

Pergunta: Qual é a maneira mais eficiente de resolver esse problema? Se o loop estiver correto, há espaço para melhorias?

Eu usei um loop e # tabelas temporárias, aqui minha solução:

set rowcount 0
-- THE SOURCE TABLE "LINE" HAS THE SAME SCHEMA AS #RESULT AND #TEMP
use Northwind
go

declare @sum int
declare @curr int
set @sum = 0
declare @id int

IF OBJECT_ID('tempdb..#temp','u') IS NOT NULL
    DROP TABLE #temp

IF OBJECT_ID('tempdb..#result','u') IS NOT NULL
    DROP TABLE #result

create table #result( 
    id int not null,
    [name] varchar(255) not null,
    weight int not null,
    turn int not null
)

create table #temp( 
    id int not null,
    [name] varchar(255) not null,
    weight int not null,
    turn int not null
)

INSERT into #temp SELECT * FROM line order by turn

 WHILE EXISTS (SELECT 1 FROM #temp)
  BEGIN
   -- Get the top record
   SELECT TOP 1 @curr =  r.weight  FROM  #temp r order by turn  
   SELECT TOP 1 @id =  r.id  FROM  #temp r order by turn

    --print @curr
    print @sum

    IF(@sum + @curr <= 1000)
    BEGIN
    print 'entering........ again'
    --print @curr
      set @sum = @sum + @curr
      --print @sum
      INSERT INTO #result SELECT * FROM  #temp where [id] = @id  --id, [name], turn
      DELETE FROM #temp WHERE id = @id
    END
     ELSE
    BEGIN    
    print 'breaaaking.-----'
      BREAK
    END 
  END

   SELECT TOP 1 [name] FROM #result r order by r.turn desc 

Aqui, o script Create para a tabela que usei Northwind para testar:

USE [Northwind]
GO

/****** Object:  Table [dbo].[line]    Script Date: 28.05.2018 21:56:18 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[line](
    [id] [int] NOT NULL,
    [name] [varchar](255) NOT NULL,
    [weight] [int] NOT NULL,
    [turn] [int] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
UNIQUE NONCLUSTERED 
(
    [turn] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[line]  WITH CHECK ADD CHECK  (([weight]>(0)))
GO

INSERT INTO [dbo].[line]
    ([id], [name], [weight], [turn])
VALUES
    (5, 'gary', 800, 1),
    (3, 'jo', 350, 2),
    (6, 'thomas', 400, 3),
    (2, 'will', 200, 4),
    (4, 'mark', 175, 5),
    (1, 'james', 100, 6)
;
Legendas
fonte

Respostas:

16

Você deve tentar evitar loops em geral. Eles são normalmente menos eficientes que as soluções baseadas em conjuntos e menos legíveis.

O abaixo deve ser bastante eficiente.

Ainda mais se as colunas de nome e peso pudessem ser INCLUDE-d no índice para evitar as principais pesquisas.

Ele pode varrer o índice exclusivo em ordem turne calcular o total de execução da Weightcoluna - depois use LEADcom os mesmos critérios de pedido para ver qual será o total de execução na próxima linha.

Assim que encontrar a primeira linha em que isso excede 1000 ou está NULL(indicando que não há próxima linha), poderá interromper a verificação.

WITH T1
     AS (SELECT *,
                SUM(Weight) OVER (ORDER BY turn ROWS UNBOUNDED PRECEDING) AS cume_weight
         FROM   [dbo].[line]),
     T2
     AS (SELECT LEAD(cume_weight) OVER (ORDER BY turn) AS next_cume_weight,
                *
         FROM   T1)
SELECT TOP 1 name
FROM   T2
WHERE  next_cume_weight > 1000
        OR next_cume_weight IS NULL
ORDER  BY turn 

Plano de execução

insira a descrição da imagem aqui

Na prática, parece ler algumas linhas à frente de onde é estritamente necessário - parece que cada par agregado de spool / fluxo de janela faz com que duas linhas adicionais sejam lidas.

Para os dados de amostra na pergunta, idealmente, seria necessário ler apenas duas linhas da varredura de índice, mas na realidade lê 6, mas esse não é um problema de eficiência significativo e não é degradado à medida que mais linhas são adicionadas à tabela (como em esta demonstração )

Para os interessados nesta questão uma imagem com a saída linhas por cada operador (como mostrado pelo query_trace_column_valuesevento estendido) está abaixo, as linhas são mostradas em row_idordem (a partir de 47para a primeira linha lido pelo índice de digitalização e terminando no 113para o TOP)

Clique na imagem abaixo para aumentá-la ou veja a versão animada para facilitar o acompanhamento do fluxo .

Pausar a animação no ponto em que o fluxo do lado direito agregou sua primeira linha (para gary - turn = 1). Parece aparente que estava esperando para receber sua primeira linha com um WindowCount diferente (para Jo-turn = 2). E o spool da janela não libera a primeira linha "Jo" até que ela leia a próxima linha com uma diferente turn(para thomas - turn = 3)

Portanto, o spool de janela e o fluxo agregado fazem com que uma linha adicional seja lida e há quatro delas no plano - daí quatro linhas adicionais.

insira a descrição da imagem aqui

A seguir, é apresentada uma explicação das colunas mostradas acima (com base nas informações aqui )

  • NodeName: Varredura de Índice, NodeId: 15, ColumnName: coluna da tabela base de identificação coberta pelo índice
  • NodeName: Varredura de Índice, NodeId: 15, ColumnName: vira a coluna da tabela base coberta pelo índice
  • NodeName: busca de índice em cluster, NodeId: 17, ColumnName: coluna da tabela de base de peso recuperada da pesquisa
  • NodeName: busca de índice em cluster, NodeId: 17, ColumnName: coluna da tabela base de nome recuperada da pesquisa
  • NodeName: Segment, NodeId: 13, ColumnName: Segment1010 Retorna 1 no início do novo grupo ou nulo, caso contrário. Como não Partition By, SUMapenas a primeira linha recebe 1
  • NodeName: Sequence Project, NodeId: 12, ColumnName: RowNumber1009 row_number() dentro do grupo indicado pelo sinalizador Segment1010. Como todas as linhas estão no mesmo grupo, são números inteiros ascendentes de 1 a 6. Seriam usados ​​para filtrar as linhas do quadro direito em casos como esse rows between 5 preceding and 2 following. (ou mais LEADtarde)
  • NodeName: Segment, NodeId: 11, ColumnName: Segment1011 Retorna 1 no início do novo grupo ou nulo, caso contrário. Como não Partition By, SUMapenas a primeira linha recebe 1 (o mesmo que o segmento1010)
  • NodeName: Spool da janela, NodeId: 10, ColumnName: WindowCount1012 Atributo que agrupa linhas pertencentes a um quadro de janela. Este spool de janela está usando o caso "fast track" para UNBOUNDED PRECEDING. Onde emite duas linhas por linha de origem. Um com os valores cumulativos e outro com os valores detalhados. Embora não haja diferença visível nas linhas expostas por query_trace_column_values, assumo que as colunas cumulativas existem na realidade.
  • NodeName: fluxo agregado, NodeId: 9, ColumnName: Expr1004 Count(*) agrupado por WindowCount1012 de acordo com o plano, mas na verdade uma contagem em execução
  • NodeName: Stream Aggregate, NodeId: 9, ColumnName: Expr1005 SUM(weight) agrupado por WindowCount1012 de acordo com o plano, mas na verdade a soma do peso em execução (por exemplo cume_weight)
  • NodeName: Segment, NodeId: 7, ColumnName: Expr1002 CASE WHEN [Expr1004]=(0) THEN NULL ELSE [Expr1005] END - Não vê como COUNT(*)pode ser 0, portanto sempre estará executando sum ( cume_weight)
  • NodeName: Segment, NodeId: 7, ColumnName: Segment1013 Não partition byna LEADprimeira linha, obtém 1. Todos os restantes são nulos
  • NodeName: Sequence Project, NodeId: 6, ColumnName: RowNumber1006 row_number() dentro do grupo indicado pelo sinalizador Segment1013. Como todas as linhas estão no mesmo grupo, são números inteiros ascendentes de 1 a 4
  • NodeName: Segmento, NodeId: 4, ColumnName: BottomRowNumber1008 RowNumber1006 + 1, pois LEADrequer a próxima linha única
  • NodeName: Segmento, NodeId: 4, ColumnName: TopRowNumber1007 RowNumber1006 + 1, pois LEADrequer a próxima linha única
  • NodeName: Segment, NodeId: 4, ColumnName: Segment1014 Não partition byna LEADprimeira linha, obtém 1. Todos os restantes são nulos
  • NodeName: Spool da janela, NodeId: 3, ColumnName: WindowCount1015 Atributo que agrupa linhas pertencentes a um quadro de janela usando os números de linha anteriores. O quadro da janela para LEADtem no máximo 2 linhas (a atual e a próxima)
  • NodeName: fluxo agregado, NodeId: 2, ColumnName: Expr1003 LAST_VALUE([Expr1002]) para oLEAD(cume_weight)
Martin Smith
fonte
6

Assim como uma curiosidade (como a pergunta indica T-SQL), também é possível resolver esse problema com eficiência usando o SQLCLR.

A idéia é ler as linhas uma por vez turn, até que weightexceda 1000 (ou ficamos sem linhas) e, em seguida, retorne a última nameleitura.

O código fonte é:

using Microsoft.SqlServer.Server;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;

public partial class UserDefinedFunctions
{
    [SqlFunction(DataAccess = DataAccessKind.Read,
        SystemDataAccess = SystemDataAccessKind.None,
        IsDeterministic = true, IsPrecise = true)]
    [return: SqlFacet(IsFixedLength = false, IsNullable = true, MaxSize = 255)]
    public static SqlString Elevator()
    {
        const string query =
            @"SELECT L.[name], L.[weight]
            FROM dbo.line AS L
            ORDER BY L.turn;";

        using (var con = new SqlConnection("context connection = true"))
        {
            con.Open();
            using (var cmd = new SqlCommand(query, con))
            {
                var rdr = cmd.ExecuteReader(CommandBehavior.SingleResult);
                var name = SqlString.Null;
                var total = 0;

                while (rdr.Read() && (total += rdr.GetInt32(1)) <= 1000)
                {
                    name = rdr.GetSqlString(0);
                }
                return name;
            }
        }
    }
}

O assembly compilado e a função T-SQL:

CREATE ASSEMBLY Elevator AUTHORIZATION [dbo]
FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C010300606C0E5B0000000000000000E00022200B013000000C000000060000000000004A2A0000002000000040000000000010002000000002000004000000000000000600000000000000008000000002000000000000030060850000100000100000000010000010000000000000100000000000000000000000F82900004F00000000400000A802000000000000000000000000000000000000006000000C000000C02800001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000500A000000200000000C000000020000000000000000000000000000200000602E72737263000000A80200000040000000040000000E0000000000000000000000000000400000402E72656C6F6300000C00000000600000000200000012000000000000000000000000000040000042000000000000000000000000000000002C2A0000000000004800000002000500F0200000D007000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001B30030070000000010000117201000070730600000A0A066F0700000A723500007006730800000A0B07176F0900000A0C7E0A00000A0D1613042B0808166F0B00000A0D086F0C00000A2C14110408176F0D00000A5825130420E803000031DC091305DE14072C06076F0E00000ADC062C06066F0E00000ADC11052A011C000002001D003C59000A0000000002000B005863000A000000001E02280F00000A2A42534A4201000100000000000C00000076342E302E33303331390000000005006C000000AC010000237E0000180200002002000023537472696E677300000000380400008801000023555300C0050000100000002347554944000000D00500000002000023426C6F620000000000000002000001471502000900000000FA01330016000001000000110000000200000002000000010000000F000000050000000200000001000000020000000000E70001000000000006008A00A9010600BC00A9010600610096010F00C901000006000202F9000A0075005C010A003E005C010A0038005C010A00AA005C010A00DD00D8010A00120109020A002D0009020A00400109020A00050120010A00770113000A003301200106004D00F900000000000A00000000000100010001001000ED0100001500010001005020000000009600870150000100E820000000008618900106000200000000000000090090010100110090010600190090010A00310090010600490090010600590090011E0071000001060061009001230061004E012A005100F40031006900DA003500810028003B00810001003F0089005900060029009001060020002300860024002B00CE012E000B0055002E0013005E002E001B007D00100044000480000000000000000000000000000000008701000004000000000000000000000047001F000000000004000000000000000000000047001300000000000000000000476574496E743332003C4D6F64756C653E0053797374656D2E44617461006D73636F726C696200526561640053716C436F6D6D616E640053797374656D446174614163636573734B696E640049446973706F7361626C6500446973706F73650044656275676761626C654174747269627574650053716C46756E6374696F6E41747472696275746500436F6D70696C6174696F6E52656C61786174696F6E734174747269627574650053716C46616365744174747269627574650052756E74696D65436F6D7061746962696C6974794174747269627574650047657453716C537472696E6700456C657661746F722E646C6C004E756C6C0053797374656D004F70656E004462436F6E6E656374696F6E0053716C436F6E6E656374696F6E0053797374656D2E446174612E436F6D6D6F6E004462446174615265616465720053716C446174615265616465720045786563757465526561646572004D6963726F736F66742E53716C5365727665722E53657276657200436F6D6D616E644265686176696F7200456C657661746F72002E63746F720053797374656D2E446961676E6F73746963730053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300446562756767696E674D6F6465730053797374656D2E446174612E53716C54797065730055736572446566696E656446756E6374696F6E73004F626A6563740053797374656D2E446174612E53716C436C69656E740000003363006F006E007400650078007400200063006F006E006E0065006300740069006F006E0020003D00200074007200750065000081510D000A00200020002000200020002000200020002000200020002000530045004C004500430054000D000A0020002000200020002000200020002000200020002000200020002000200020004C002E005B006E0061006D0065005D002C000D000A0020002000200020002000200020002000200020002000200020002000200020004C002E005B007700650069006700680074005D000D000A00200020002000200020002000200020002000200020002000460052004F004D002000640062006F002E006C0069006E00650020004100530020004C000D000A002000200020002000200020002000200020002000200020004F0052004400450052002000420059000D000A0020002000200020002000200020002000200020002000200020002000200020004C002E007400750072006E003B000D000A00200020002000200020002000200020002000200020002000006C68AC85076C6945BCECB2CE73B9787F000420010108032000010520010111110D0706122D123112351129081129042001010E062002010E122D0620011235113D0306112905200111290803200002042001080802060E08B77A5C561934E08904000011290801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F7773010801000200000000008146010004005455794D6963726F736F66742E53716C5365727665722E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A446174614163636573730100000054557F4D6963726F736F66742E53716C5365727665722E5365727665722E53797374656D446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038391053797374656D446174614163636573730000000054020F497344657465726D696E69737469630154020949735072656369736501310100030054020D497346697865644C656E6774680054020A49734E756C6C61626C65015408074D617853697A65FF00000000000000606C0E5B00000000020000001C010000DC280000DC0A000052534453F8D0A90B6069F74DB5FBFABECC9D213901000000633A5C75736572735C7061756C775C736F757263655C7265706F735C4461746162617365325C4461746162617365325C6F626A5C52656C656173655C456C657661746F722E7064620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000202A000000000000000000003A2A00000020000000000000000000000000000000000000000000002C2A0000000000000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF2500200010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001001000000018000080000000000000000000000000000001000100000030000080000000000000000000000000000001000000000048000000584000004C02000000000000000000004C0234000000560053005F00560045005200530049004F004E005F0049004E0046004F0000000000BD04EFFE00000100000000000000000000000000000000003F000000000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F00000000002400040000005400720061006E0073006C006100740069006F006E00000000000000B004AC010000010053007400720069006E006700460069006C00650049006E0066006F0000008801000001003000300030003000300034006200300000002C0002000100460069006C0065004400650073006300720069007000740069006F006E000000000020000000300008000100460069006C006500560065007200730069006F006E000000000030002E0030002E0030002E00300000003A000D00010049006E007400650072006E0061006C004E0061006D006500000045006C0065007600610074006F0072002E0064006C006C00000000002800020001004C006500670061006C0043006F00700079007200690067006800740000002000000042000D0001004F0072006900670069006E0061006C00460069006C0065006E0061006D006500000045006C0065007600610074006F0072002E0064006C006C0000000000340008000100500072006F006400750063007400560065007200730069006F006E00000030002E0030002E0030002E003000000038000800010041007300730065006D0062006C0079002000560065007200730069006F006E00000030002E0030002E0030002E0030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000C0000004C3A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
WITH PERMISSION_SET = SAFE;
GO
CREATE FUNCTION dbo.Elevator ()
RETURNS nvarchar(255)
AS EXTERNAL NAME Elevator.UserDefinedFunctions.Elevator;

Obtendo o resultado:

SELECT dbo.Elevator();
Paul White 9
fonte
1

Ligeira variação da solução de Martin Smith

SELECT top 1 name
FROM (
    SELECT id, name, weight, turn
         , SUM(weight) OVER (ORDER BY turn) AS cumulative_weight
    FROM line                               
) as T
WHERE cumulative_weight <= 1000
ORDER BY turn DESC 

RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW é o quadro da janela padrão, então não declarei isso.

Um predicado para o peso acumulado atual é usado em vez do próximo peso cumulativo.

Eu não verifiquei nenhum plano, então não sei dizer se há alguma diferença a esse respeito.

Lennart
fonte
Entendo, estou cercado por geeks da DB :-). Eu tenho que verificar todas as palavras-chave que vocês mencionam para entender o que elas fazem. Eu só dei uma olhada Client statistics --> Total Execution Time, não a Actual execution planque provavelmente é a mais interessante aqui. A partir da Client Statisticssua solução, é um pouco mais lenta que a de Martin. Obrigado pela informação adicional. Qual método pode ser usado para medir diferenças de desempenho entre diferentes abordagens?
Legends
11
Receio que meu conhecimento sobre o servidor SQL seja muito limitado, por isso não tenho muitas informações sobre quais métricas usar. Martin tem um link de violão db <> em sua resposta, talvez você possa ver os planos lá.
Lennart 30/05
11
Também não verifiquei os planos, mas imaginaria que isso provavelmente calculará o total em execução em toda a tabela e classificará as linhas resultantes correspondentes ao WHERE. Duvido que ele use a restrição de verificação para saber que o total atual é estritamente ascendente e pode parar mais cedo. Também em SQL Server, excepto quando o agregado janela do modo em lote é usado especificando ROWS em vez de intervalo é preferível, mesmo onde não existem duplicatas como o carretel janela está na memória não disc
Martin Smith
@ MartinSmith, interessante. Na sua solução, o LEAD torna possível enviar o predicado next_cume_weight <10000 dentro do T1 e resgatar antecipadamente a verificação do índice? Eu verifiquei o plano da minha consulta e ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROWintroduzi um Sequence Project (Compute Scalar)operador. Escusado será dizer que eu não tenho idéia o que isso significa :-)
Lennart
11
O índice entrega as linhas na ordem necessária pela soma, lead e top. Assim que top recebe sua primeira linha, ele pode parar de solicitar mais linhas e a execução pode parar.
Martin Smith
0

Você pode fazer uma junção contra si mesma:

select 
    a.id, a.turn, a.game, 
    coalesce(sum(b.weight), 0) as cumulative_weight
from
    table a
left join 
    table b
on
    a.turn > b.turn
group by
    a.id, a.turn, a.game ;

Esse tipo de coisa não é muito eficiente, pois causa uma seleção por linha. Mas pelo menos é expresso como uma única declaração.

Se você não precisar fazer isso totalmente no SQL, poderá simplesmente selecionar todas as linhas e percorrê-las, adicionando à medida que avança.

Você poderia fazer o mesmo em um procedimento armazenado sem a tabela temporária também. Apenas segure a soma e o último nome da linha em uma variável.

ypercubeᵀᴹ
fonte
Desculpe, não sei como fazê-lo funcionar com a self-join. Se você puder fazer um pequeno exemplo reproduzível, adicionei a definição da tabela à minha pergunta. Meu sql está ruim .... Preciso do nome da pessoa mais próxima a <= 1000 lbs.
Legends
parece que sua atualização funciona bem, você precisará mexer um pouco com ela se quiser que ela produza exatamente a saída exata. Mas como eu digo, não é super-eficiente
OK? Eu fico nulo para a pessoa com o id 5 ...
Legends
que é estranho, eu esperaria sum () para retornar 0 para uma soma sobre linhas 0
SOMA acima de 0 linhas não é 0 (infelizmente). Você precisa usar COALESCE()ou ISNULL()função ou uma CASEexpressão para torná-lo 0.
ypercubeᵀᴹ