Em conseguiu uma tarefa de programação na área de T-SQL
.
Tarefa:
- As pessoas querem entrar no elevador, cada pessoa tem um certo peso.
- A ordem das pessoas que estão na fila é determinada pelo giro da coluna.
- O elevador tem uma capacidade máxima de <= 1000 lbs.
- Retorne o nome da última pessoa que pode entrar no elevador antes que fique muito pesado!
- O tipo de retorno deve ser tabela
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)
;
fonte
Client statistics --> Total Execution Time
, não aActual execution plan
que provavelmente é a mais interessante aqui. A partir daClient Statistics
sua 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?ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
introduzi umSequence Project (Compute Scalar)
operador. Escusado será dizer que eu não tenho idéia o que isso significa :-)Você pode fazer uma junção contra si mesma:
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.
fonte
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.COALESCE()
ouISNULL()
função ou umaCASE
expressão para torná-lo 0.