T-SQL - Apa cara paling efisien untuk mengulang tabel sampai kondisi terpenuhi

10

Dalam mendapat tugas pemrograman di bidang T-SQL.

Tugas:

  1. Orang ingin masuk ke dalam lift setiap orang memiliki berat tertentu.
  2. Urutan orang-orang yang mengantri ditentukan oleh giliran kolom.
  3. Lift memiliki kapasitas maksimal <= 1000 lbs.
  4. Kembalikan nama orang terakhir yang bisa masuk lift sebelum terlalu berat!
  5. Jenis pengembalian harus berupa tabel

masukkan deskripsi gambar di sini

Pertanyaan: Apa cara paling efisien untuk menyelesaikan masalah ini? Jika perulangan benar, apakah ada ruang untuk perbaikan?

Saya menggunakan loop dan tabel # temp, di sini solusi saya:

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 

Di sini skrip Buat untuk tabel yang saya gunakan Northwind untuk pengujian:

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

Jawaban:

16

Anda harus mencoba menghindari loop secara umum. Mereka biasanya kurang efisien daripada solusi berbasis set serta kurang mudah dibaca.

Di bawah ini seharusnya cukup efisien.

Terlebih lagi jika kolom nama dan berat bisa INCLUDE-d dalam indeks untuk menghindari pencarian kunci.

Itu dapat memindai indeks unik secara berurutan turndan menghitung jumlah Weightkolom yang berjalan - kemudian gunakan LEADdengan kriteria pemesanan yang sama untuk melihat berapa jumlah total yang berjalan pada baris berikutnya.

Begitu menemukan baris pertama di mana ini melebihi 1000 atau berada NULL(menunjukkan tidak ada baris berikutnya) maka dapat menghentikan pemindaian.

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 

Rencana eksekusi

masukkan deskripsi gambar di sini

Dalam prakteknya tampaknya membaca beberapa baris di depan di mana sangat diperlukan - sepertinya setiap pasangan agregat / aliran jendela menyebabkan dua baris tambahan dibaca.

Untuk data sampel dalam pertanyaan idealnya hanya perlu membaca dua baris dari pemindaian indeks tetapi pada kenyataannya itu membaca 6 tetapi ini bukan masalah efisiensi yang signifikan dan tidak menurun karena lebih banyak baris ditambahkan ke tabel (seperti pada demo ini )

Bagi mereka yang tertarik dengan masalah ini, sebuah gambar dengan output baris oleh masing-masing operator (seperti yang ditunjukkan oleh query_trace_column_valuesevent yang diperluas) ada di bawah, baris adalah output secara row_idberurutan (mulai dari 47untuk baris pertama dibaca oleh pemindaian indeks dan finishing di 113untuk TOP)

Klik gambar di bawah untuk membuatnya lebih besar atau sebagai alternatif melihat versi animasi untuk membuat aliran lebih mudah diikuti .

Menjeda animasi pada titik di mana agregat aliran kanan telah memancarkan baris pertama (untuk gary - turn = 1). Tampak jelas bahwa ia menunggu untuk menerima baris pertama dengan WindowCount yang berbeda (untuk Jo - turn = 2). Dan kumparan jendela tidak melepaskan baris "Jo" pertama sampai telah membaca baris berikutnya dengan yang berbeda turn(untuk thomas - turn = 3)

Jadi kumparan jendela dan aliran agregat keduanya menyebabkan baris tambahan untuk dibaca dan ada empat dari ini dalam rencana - karenanya 4 baris tambahan.

masukkan deskripsi gambar di sini

Penjelasan dari kolom yang ditunjukkan di bawah ini (berdasarkan info di sini )

  • NodeName: Pemindaian Indeks, NodeId: 15, ColumnName: kolom tabel dasar id yang dicakup oleh indeks
  • NodeName: Pemindaian Indeks, NodeId: 15, ColumnName: giliran kolom tabel dasar yang dicakup oleh indeks
  • NodeName: Clustered Index Seek, NodeId: 17, ColumnName: kolom tabel basis berat diambil dari pencarian
  • NodeName: Clustered Index Seek, NodeId: 17, ColumnName: nama tabel tabel kolom diambil dari pencarian
  • NodeName: Segment, NodeId: 13, ColumnName: Segment1010 Mengembalikan 1 pada awal grup baru atau nol jika tidak. Karena tidak Partition Bydi SUMbaris pertama saja mendapat 1
  • NodeName: Sequence Project, NodeId: 12, ColumnName: RowNumber1009 row_number() dalam grup yang ditandai dengan flag Segment1010. Karena semua baris berada di grup yang sama, ini adalah bilangan bulat naik dari 1 menjadi 6. Akan digunakan untuk memfilter baris frame kanan dalam kasus seperti rows between 5 preceding and 2 following. (atau untuk LEADnanti)
  • NodeName: Segment, NodeId: 11, ColumnName: Segment1011 Mengembalikan 1 pada awal grup baru atau nol sebaliknya. Karena tidak Partition Bydi SUMbaris pertama saja mendapat 1 (Sama dengan Segment1010)
  • NodeName: Spool Jendela, NodeId: 10, ColumnName: WindowCount1012 Atribut bahwa grup-grup bersama-sama baris milik bingkai jendela. Spool jendela ini menggunakan case "fast track" untuk UNBOUNDED PRECEDING. Di mana ia memancarkan dua baris per baris sumber. Satu dengan nilai kumulatif dan satu dengan nilai detail. Meskipun tidak ada perbedaan yang terlihat dalam baris yang diekspos oleh query_trace_column_valuessaya berasumsi bahwa kolom kumulatif ada dalam kenyataannya.
  • NodeName: Stream Aggregate, NodeId: 9, ColumnName: Expr1004 Count(*) dikelompokkan oleh WindowCount1012 menurut rencana tetapi sebenarnya hitungan berjalan
  • NodeName: Stream Aggregate, NodeId: 9, ColumnName: Expr1005 SUM(weight) dikelompokkan berdasarkan WindowCount1012 sesuai dengan rencana tetapi sebenarnya jumlah menjalankan bobot (yaitu cume_weight)
  • NodeName: Segment, NodeId: 7, ColumnName: Expr1002 CASE WHEN [Expr1004]=(0) THEN NULL ELSE [Expr1005] END - Tidak melihat bagaimana COUNT(*)bisa 0 sehingga akan selalu menjalankan jumlah ( cume_weight)
  • NodeName: Segment, NodeId: 7, ColumnName: Segment1013 Tidak partition bydi LEADbaris pertama jadi 1. Semua yang tersisa dapatkan nol
  • NodeName: Sequence Project, NodeId: 6, ColumnName: RowNumber1006 row_number() dalam grup yang ditunjukkan oleh flag Segment1013. Karena semua baris berada di grup yang sama, ini adalah bilangan bulat naik dari 1 ke 4
  • NodeName: Segmen, NodeId: 4, ColumnName: BottomRowNumber1008 RowNumber1006 + 1 karena LEADmemerlukan satu baris berikutnya
  • NodeName: Segmen, NodeId: 4, ColumnName: TopRowNumber1007 RowNumber1006 + 1 karena LEADmemerlukan satu baris berikutnya
  • NodeName: Segment, NodeId: 4, ColumnName: Segment1014 Tidak partition bydi LEADbaris pertama jadi 1. Semua yang tersisa dapatkan nol
  • NodeName: Spool Jendela, NodeId: 3, ColumnName: WindowCount1015 Atribut bahwa grup bersama-sama baris milik bingkai jendela menggunakan nomor baris sebelumnya. Bingkai jendela untuk LEADmemiliki maksimal 2 baris (yang sekarang dan yang berikutnya)
  • NodeName: Stream Aggregate, NodeId: 2, ColumnName: Expr1003 LAST_VALUE([Expr1002]) untukLEAD(cume_weight)
Martin Smith
sumber
6

Sama seperti rasa ingin tahu (karena pertanyaan menyatakan T-SQL) juga dimungkinkan untuk memecahkan masalah ini secara efisien menggunakan SQLCLR.

Idenya adalah membaca baris satu per satu secara turnberurutan hingga weightmelebihi 1000 (atau kita kehabisan baris), lalu mengembalikan namepembacaan terakhir .

Kode sumbernya adalah:

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

Rakitan yang dikompilasi dan fungsi 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;

Mendapatkan hasilnya:

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

Sedikit variasi dari solusi 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 adalah bingkai jendela default jadi saya tidak menyatakan itu.

Predikat untuk bobot kumulatif saat ini digunakan sebagai ganti berat kumulatif berikutnya.

Saya belum memeriksa rencana apa pun, jadi saya tidak tahu apakah ada perbedaan dalam hal itu.

Lennart
sumber
Begitu ya, saya dikelilingi oleh Geeks DB :-). Saya harus memeriksa semua kata kunci yang kalian sebutkan untuk memahami apa yang mereka lakukan. Saya hanya melihat Client statistics --> Total Execution Time, bukan Actual execution planyang mungkin paling menarik di sini. Sebagai Client Statisticssolusi Anda sedikit lebih lambat maka Martin. Terima kasih atas info tambahannya. Metode mana yang dapat digunakan untuk mengukur perbedaan kinerja antara berbagai pendekatan?
Legenda
1
Saya khawatir pengetahuan saya tentang SQL-server sangat terbatas sehingga saya tidak memiliki banyak wawasan tentang metrik apa yang digunakan. Martin memiliki db <> tautan biola dalam jawabannya, mungkin Anda dapat melihat rencananya di sana.
Lennart
1
saya belum memeriksa rencana baik tetapi akan membayangkan bahwa ini mungkin akan menghitung total berjalan di seluruh tabel dan kemudian mengurutkan baris yang cocok dengan WHERE. Saya ragu bahwa itu akan menggunakan batasan cek untuk mengetahui bahwa total berjalan benar-benar naik dan dapat berhenti lebih awal. Juga di SQL Server kecuali di mana agregat jendela mode batch digunakan menentukan ROWS daripada RANGE lebih disukai bahkan di mana tidak ada duplikat karena kumparan jendela dalam memori tidak disc
Martin Smith
@ MartinSmith, menarik. Dalam solusi Anda, LEAD memungkinkan untuk mendorong predikat next_cume_weight <10000 di dalam T1 dan menebus lebih awal dari pemindaian indeks? Saya memeriksa rencana untuk pertanyaan saya dan ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROWmemperkenalkan Sequence Project (Compute Scalar), operator. Tidak perlu dikatakan saya tidak tahu apa artinya ini :-)
Lennart
1
Indeks memberikan baris dalam urutan yang dibutuhkan oleh jumlah, timah, dan atas. Segera setelah top menerima baris pertama, ia dapat berhenti meminta lagi baris dan eksekusi dapat berhenti.
Martin Smith
0

Anda bisa melakukan join sendiri:

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 ;

Hal semacam ini tidak terlalu efisien karena menyebabkan pilih per baris. Tapi setidaknya itu dinyatakan sebagai satu pernyataan.

Jika Anda tidak harus melakukannya sepenuhnya dalam SQL maka Anda dapat dengan mudah memilih semua baris dan mengulanginya, menambahkan saat Anda pergi.

Anda bisa melakukan hal yang sama dalam prosedur tersimpan tanpa tabel temp juga. Cukup tahan jumlah dan nama baris terakhir dalam sebuah variabel.

ypercubeᵀᴹ
sumber
Maaf, saya tidak tahu bagaimana cara membuatnya bekerja dengan self-join, jika Anda bisa membuat contoh kecil yang dapat direproduksi, saya telah menambahkan definisi tabel ke pertanyaan saya. Sql saya jelek .... Saya perlu nama orang yang paling dekat dengan <= 1000 lbs.
Legenda
Sepertinya pembaruan Anda berfungsi dengan baik, Anda harus sedikit bermain-main dengannya jika Anda ingin menghasilkan output yang tepat. Tapi seperti yang saya katakan, itu tidak sangat efisien
Baik? Saya mendapatkan null untuk Person dengan id 5 ...
Legends
itu aneh, saya akan mengharapkan jumlah () mengembalikan 0 untuk jumlah lebih dari 0 baris
SUM lebih dari 0 baris bukan 0 (sayangnya). Anda perlu menggunakan COALESCE()atau ISNULL()fungsi atau CASEekspresi untuk membuatnya 0.
ypercubeᵀᴹ