T-SQL: qual è il modo più efficiente per scorrere una tabella fino a quando non viene soddisfatta una condizione


10

In ha ottenuto un compito di programmazione nell'area di T-SQL.

Compito:

  1. Le persone vogliono entrare in un ascensore ogni persona ha un certo peso.
  2. L'ordine delle persone in attesa in linea è determinato dalla svolta della colonna.
  3. L'ascensore ha una capacità massima di <= 1000 libbre.
  4. Restituisci il nome dell'ultima persona che è in grado di entrare nell'ascensore prima che diventi troppo pesante!
  5. Il tipo restituito dovrebbe essere tabella

inserisci qui la descrizione dell'immagine

Domanda: Qual è il modo più efficace per risolvere questo problema? Se il looping è corretto, c'è qualche margine di miglioramento?

Ho usato un ciclo e tabelle # temp, qui la mia soluzione:

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 

Ecco lo script Crea per la tabella che ho usato Northwind per i test:

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)
;

Risposte:


16

Dovresti cercare di evitare i loop in generale. Di solito sono meno efficienti delle soluzioni basate su set e meno leggibili.

Quanto sotto dovrebbe essere abbastanza efficiente.

Ancor di più se le colonne nome e peso potrebbero essere INCLUDE-d nell'indice per evitare le ricerche chiave.

Può scansionare l'indice univoco in ordine turne calcolare il totale Weightparziale della colonna, quindi utilizzare LEADcon gli stessi criteri di ordinamento per vedere quale sarà il totale parziale nella riga successiva.

Non appena trova la prima riga dove questa supera 1000 o è NULL(indicando che non vi è alcuna riga successiva), può interrompere la scansione.

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 

Progetto esecutivo

inserisci qui la descrizione dell'immagine

In pratica sembra leggere alcune righe davanti a dove è strettamente necessario - sembra che ogni coppia aggregata di spool / stream della finestra faccia leggere due righe aggiuntive.

Idealmente, per i dati di esempio nella domanda dovrebbe solo leggere due righe dalla scansione dell'indice ma in realtà legge 6 ma questo non è un problema di efficienza significativo e non si degrada poiché vengono aggiunte più righe alla tabella (come in questa demo )

Per chi è interessato in questo numero un'immagine con l'uscita righe da ciascun operatore (come mostrato dalla query_trace_column_valuesmanifestazione esteso) è inferiore, le righe vengono emessi in row_idordine (iniziando a 47per la prima riga letta dal indice di scansione e finitura a 113per il TOP)

Fare clic sull'immagine qui sotto per ingrandirla o in alternativa vedere la versione animata per facilitare il flusso .

Mettere in pausa l'animazione nel punto in cui l'aggregato del flusso a destra ha emesso la sua prima riga (per gary - turn = 1). Sembra evidente che fosse in attesa di ricevere la sua prima riga con un WindowCount diverso (per Jo - turn = 2). E il rocchetto della finestra non rilascia la prima riga "Jo" fino a quando non ha letto la riga successiva con una diversa turn(per thomas - turn = 3)

Pertanto, sia lo spool della finestra che l'aggregazione del flusso causano la lettura di una riga aggiuntiva e ce ne sono quattro nel piano, quindi 4 righe aggiuntive.

inserisci qui la descrizione dell'immagine

Segue una spiegazione delle colonne mostrate sopra (in base alle informazioni qui )

  • NodeName: Index Scan, NodeId: 15, ColumnName: colonna della tabella di base id coperta dall'indice
  • NodeName: Index Scan, NodeId: 15, ColumnName: gira la colonna della tabella di base coperta dall'indice
  • NodeName: Ricerca indice cluster, NodeId: 17, ColumnName: colonna della tabella della base di peso recuperata dalla ricerca
  • NodeName: Ricerca indice cluster, NodeId: 17, ColumnName: colonna della tabella della base dei nomi recuperata dalla ricerca
  • NodeName: Segment, NodeId: 13, ColumnName: Segment1010 Restituisce 1 all'inizio del nuovo gruppo o null altrimenti. Poiché non Partition Bynel SUMsolo la prima fila ottiene 1
  • NodeName: Progetto sequenza, NodeId: 12, ColumnName: RowNumber1009 row_number() all'interno del gruppo indicato dal flag Segment1010. Dato che tutte le righe sono nello stesso gruppo, si tratta di numeri interi crescenti da 1 a 6. Sarebbe usato per filtrare le righe del frame destro in casi come rows between 5 preceding and 2 following. (o come LEADpiù tardi)
  • NodeName: Segment, NodeId: 11, ColumnName: Segment1011 Restituisce 1 all'inizio del nuovo gruppo o null altrimenti. Poiché non Partition Bynel SUMsolo la prima fila ottiene 1 (Come Segment1010)
  • NodeName: Window Spool, NodeId: 10, ColumnName: WindowCount1012 Attributo che raggruppa le righe appartenenti a un frame della finestra. Questo spool della finestra sta usando il caso "fast track" per UNBOUNDED PRECEDING. Dove emette due righe per riga di origine. Uno con i valori cumulativi e uno con i valori di dettaglio. Sebbene non vi sia alcuna differenza visibile nelle righe esposte da, query_trace_column_valuespresumo che le colonne cumulative siano presenti nella realtà.
  • NodeName: Stream Aggregate, NodeId: 9, ColumnName: Expr1004 Count(*) raggruppati per WindowCount1012 in base al piano ma in realtà un conteggio corrente
  • NodeName: Stream Aggregate, NodeId: 9, ColumnName: Expr1005 SUM(weight) raggruppati per WindowCount1012 in base al piano ma in realtà la somma corrente del peso (es. cume_weight)
  • NodeName: Segment, NodeId: 7, ColumnName: Expr1002 CASE WHEN [Expr1004]=(0) THEN NULL ELSE [Expr1005] END - Non vedo come COUNT(*)può essere 0 quindi sarà sempre in esecuzione sum ( cume_weight)
  • NodeName: Segment, NodeId: 7, ColumnName: Segment1013 No partition bysulla LEADprima riga quindi ottiene 1. Tutti i restanti diventano null
  • NodeName: Progetto sequenza, NodeId: 6, ColumnName: RowNumber1006 row_number() all'interno del gruppo indicato dal flag Segment1013. Poiché tutte le righe sono nello stesso gruppo, si tratta di numeri interi crescenti da 1 a 4
  • NodeName: Segment, NodeId: 4, ColumnName: BottomRowNumber1008 RowNumber1006 + 1 poiché LEADrichiede la riga successiva singola
  • NodeName: Segment, NodeId: 4, ColumnName: TopRowNumber1007 RowNumber1006 + 1 poiché LEADrichiede la riga successiva singola
  • NodeName: Segment, NodeId: 4, ColumnName: Segment1014 No partition bysulla LEADprima riga quindi ottiene 1. Tutti i restanti diventano null
  • NodeName: Window Spool, NodeId: 3, ColumnName: WindowCount1015 Attributo che raggruppa le righe appartenenti a un frame della finestra utilizzando i numeri di riga precedenti. La cornice della finestra per LEADha un massimo di 2 righe (quella corrente e quella successiva)
  • NodeName: Stream Aggregate, NodeId: 2, ColumnName: Expr1003 LAST_VALUE([Expr1002]) per ilLEAD(cume_weight)

6

Proprio come una curiosità (poiché la domanda afferma T-SQL) è anche possibile risolvere questo problema in modo efficiente usando SQLCLR.

L'idea è di leggere le righe una alla volta in turnordine fino a quando non weightsuperano le 1000 (o finiamo le righe), quindi per restituire l'ultima namelettura.

Il codice sorgente è:

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;
            }
        }
    }
}

L'assieme compilato e la funzione 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;

Ottenere il risultato:

SELECT dbo.Elevator();

1

Leggera variazione rispetto alla soluzione di 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 è il telaio della finestra predefinito, quindi non l'ho dichiarato.

Viene utilizzato un predicato per il peso cumulativo corrente anziché il peso cumulativo successivo.

Non ho controllato alcun piano, quindi non posso dire se c'è una differenza al riguardo.


Vedo, sono circondato da geek DB :-). Devo controllare tutte le parole chiave che menzionate per capire cosa fanno. Ho solo dato un'occhiata Client statistics --> Total Execution Time, non quello Actual execution planche è probabilmente il più interessante qui. La Client Statisticstua soluzione è un po 'più lenta di quella di Martin. Grazie per le informazioni aggiuntive. Quale metodo può essere utilizzato per misurare le differenze di prestazioni tra approcci diversi?
Legends,

1
Temo che la mia conoscenza di SQL Server sia molto limitata, quindi non ho molte informazioni dettagliate su quali metriche usare. Martin ha un link violino nella sua risposta, forse puoi guardare i piani lì.
Lennart,

1
non ho nemmeno controllato i piani, ma immagino che questo probabilmente calcolerà il totale parziale sull'intera tabella e quindi ordinerà le righe risultanti corrispondenti a WHERE. Dubito che utilizzerà il vincolo di controllo per sapere che il totale parziale è strettamente crescente e può arrestarsi in anticipo. Anche in SQL Server tranne dove viene utilizzato l'aggregato della finestra in modalità batch specificando ROWS piuttosto che RANGE è preferibile anche in assenza di duplicati poiché lo spool della finestra è in memoria e non su disco
Martin Smith,

@MartinSmith, interessante. Nella tua soluzione LEAD ti permette di spingere il predicato next_cume_weight <10000 all'interno di T1 e uscire presto dalla scansione dell'indice? Ho controllato il piano per la mia query e ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROWintroduce un Sequence Project (Compute Scalar)operatore. Inutile dire che non ho idea di cosa significhi :-)
Lennart,

1
L'indice consegna le righe nell'ordine necessario per somma, lead e top. Non appena top riceve la prima riga, può interrompere la richiesta di ulteriori righe e l'esecuzione può essere interrotta.
Martin Smith,

0

Puoi fare un join contro se stesso:

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 ;

Questo tipo di cose non è molto efficiente in quanto provoca una selezione per riga. Ma almeno è espresso come una singola affermazione.

Se non devi farlo interamente in SQL, puoi semplicemente selezionare tutte le righe e scorrere in sequenza, aggiungendole man mano che procedi.

È possibile fare lo stesso in una stored procedure anche senza la tabella temporanea. Tieni semplicemente il nome della somma e dell'ultima riga in una variabile.


Spiacente, non so come farlo funzionare con un self-join, se potessi fare un piccolo esempio riproducibile, ho aggiunto la definizione della tabella alla mia domanda. Il mio sql è cattivo .... Ho bisogno del nome della persona più vicina a <= 1000 libbre.
Legends,

sembra che il tuo aggiornamento funzioni bene, dovrai giocarci un po 'se vuoi che produca esattamente l'output. Ma come ho detto, non è super efficace

Ok? Ottengo null per Person with id 5 ...
Legends

questo è strano, mi aspetto che sum () restituisca 0 per una somma superiore a 0 righe

SOMMA su 0 righe non è 0 (purtroppo). È necessario utilizzare COALESCE()o una ISNULL()funzione o CASEun'espressione per renderlo 0.
ypercubeᵀᴹ
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.