En a obtenu une tâche de programmation dans le domaine de T-SQL
.
Tâche:
- Les gens veulent entrer dans un ascenseur, chaque personne a un certain poids.
- L'ordre des personnes faisant la queue est déterminé par le tour de colonne.
- L'ascenseur a une capacité maximale de <= 1000 lb.
- Retournez le nom de la dernière personne qui peut entrer dans l'ascenseur avant qu'il ne soit trop lourd!
- Le type de retour doit être une table
Question: Quelle est la façon la plus efficace de résoudre ce problème? Si le bouclage est correct, y a-t-il place à amélioration?
J'ai utilisé une boucle et des tables # temp, voici ma solution:
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
Voici le script de création pour la table que j'ai utilisée Northwind pour les tests:
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)
;
la source
Client statistics --> Total Execution Time
, pas celuiActual execution plan
qui est probablement le plus intéressant ici. A partir deClient Statistics
votre solution est un petit peu plus lent que Martin. Merci pour l'information supplémentaire. Quelle méthode peut-on utiliser pour mesurer les différences de performances entre différentes approches?ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
présente unSequence Project (Compute Scalar)
opérateur,. Inutile de dire que je n'ai aucune idée de ce que cela signifie :-)Vous pouvez faire une jointure contre elle-même:
Ce genre de chose n'est pas très efficace car il provoque une sélection par ligne. Mais au moins, il est exprimé en une seule déclaration.
Si vous n'avez pas à le faire entièrement en SQL, vous pouvez simplement sélectionner toutes les lignes et les parcourir, en les additionnant au fur et à mesure.
Vous pouvez également faire de même dans une procédure stockée sans la table temporaire. Maintenez simplement la somme et le nom de la dernière ligne dans une variable.
la source
self-join
, si vous pouvez faire un petit exemple reproductible, j'ai ajouté la définition du tableau à ma question. Mon sql est mauvais .... J'ai besoin du nom de la personne la plus proche de <= 1000 lbs.COALESCE()
ou uneISNULL()
fonction ou uneCASE
expression pour le mettre à 0.