En consiguió una tarea de programación en el área de T-SQL
.
Tarea:
- La gente quiere entrar a un elevador, cada persona tiene un cierto peso.
- El orden de las personas que esperan en la fila está determinado por el giro de la columna.
- El elevador tiene una capacidad máxima de <= 1000 lbs.
- ¡Devuelve el nombre de la última persona que puede entrar al elevador antes de que sea demasiado pesado!
- El tipo de retorno debe ser table
Pregunta: ¿Cuál es la forma más eficiente de resolver este problema? Si el bucle es correcto, ¿hay margen de mejora?
Utilicé un bucle y # tablas temporales, aquí mi solución:
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
Aquí el script de creación para la tabla que usé Northwind para probar:
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)
;
fuente
Client statistics --> Total Execution Time
, no elActual execution plan
que probablemente sea el más interesante aquí. A medida queClient Statistics
su solución es un poco más lenta que la de Martin. Gracias por la información adicional. ¿Qué método se puede usar para medir las diferencias de rendimiento entre diferentes enfoques?ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
introduje unSequence Project (Compute Scalar)
operador. No hace falta decir que no tengo idea de lo que esto significa :-)Puedes hacer una unión contra sí mismo:
Este tipo de cosas no es muy eficiente, ya que provoca una selección por fila. Pero al menos se expresa como una sola declaración.
Si no tiene que hacerlo completamente en SQL, simplemente puede seleccionar todas las filas y recorrerlas, sumando a medida que avanza.
También podría hacer lo mismo en un procedimiento almacenado sin la tabla temporal. Simplemente mantenga la suma y el último nombre de fila en una variable.
fuente
self-join
, si pudiera hacer un pequeño ejemplo reproducible, he agregado la definición de tabla a mi pregunta. Mi sql es malo ... Necesito el nombre de la persona más cercana a <= 1000 lbs.COALESCE()
oISNULL()
función o unaCASE
expresión para que sea 0.