@Noob_001

Какие вам дают вопросы на собеседовании?

Доброго времени суток, товарищи.

На днях я столкнулся с поиском работы.
Позвонила фирма и девушка предложила сделать (на ее взгляд) простое и маленькое задание (смотрим на пикчу в прикрепленном файле)
Я перезвонил через 5 дней и узнал, что я ничего не умею и общаться со мной строго противопоказано руководителю :)
Ее ответ был: "работодатель не готов пригласить вас на собеседование"

Меня обманывают или надо было как -то извернуться иначе в решении данного задания ?)

a029467be26049079ef778cd8b1f5574.jpg
  • Вопрос задан
  • 705 просмотров
Решения вопроса 1
saboteur_kiev
@saboteur_kiev
software engineer
Один случай - вообще не показателен.

Бывают ошибки, бывают случайности, бывают неадекватные задания.
На этой фирме свет не сошелся. Забейте и шлите резюме на другие вакансии.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
@xaphazard
1) Как уже говорили выше очевидную вещь, задание на собеседовании - это не "сделать кое-как, чтобы работало", а "сделать максимально хорошо, чтобы показать насколько хорошо ты вообще можешь делать эту работу"
2) В условии сказано "над полями и записями таблицы допускаются любые одиночные и групповые операции". Это значит, что могут, например апдейтом уменьшить количество у части уже давно совершенных операций, или назначить каждой операции новый рандомный склад назначения. И все подобные действия нужно поддерживать. Так что задание, фактически, не выполнено.
3) Не используйте курсоры и циклы в случае, если можно решить задачу без них. Миллион инсертов по 1 строке в цикле будет работать на порядки дольше чем 1 инсерт миллиона строк. В данном случае задача решается так же без цикла.
4) А что будет, если в блоке if (@flag_in > 0 and @flag_out > 0) после выполнения первого update второй апдейт упадет с ошибкой (от недостатка памяти на сервере, например)? А что если между двумя апдейтами вклинится другой, от другого запроса? Стоит поботать транзакции и try/catch

Как бы делал я (ваще не факт, что это идеальное решение):
1) завернуть все в try блок, в catch откатывать транзакцию на точку в начале блока, если что-то пошло не так.
2) повесить ограничение на таблицу Размещение, чтобы не позволять отрицательные количества. В случае чего возникнет ошибка при вставке, отрабатывает 1)
3) В случае удалений-апдейтов - находим все склады, на которые это влияет, заново по Движению пересчитываем для них данные в Размещении. Никаких циклов, 1 запрос. (удаления можно на самом деле оптимизировать, аналогично пункту 4)
4) В случае вставки можно поступть аналогично, но можно оптимизировать и считать разницу относительно уже обработанного состояния в Размещении. Опять же, никаких циклов.
5) Заметить работодателю, что в целом постановка задачи не особо корректна: нет времени Движений, поэтому нельзя адекватно обработать ситуацию, например на склад приходило (+10)(-5)(+100), а потом заменили (-5) на (-50). В итоге сумма то на складе положительна, но был момент, когда она была < 0.

Вообще на вашем месте я бы переписал решение максимально хорошо, просто для повышения своей квалификации. Здесь смогут дать мнение, насколько лучше стало. Плюс поботать try-catch и транзакции. Плюс избавляться от "программистского" стиля в SQL коде - если есть циклы и куча if, значит что-то скорее всего сделано не так.
Ответ написан
@dmitryKovalskiy
программист средней руки
Справедливости ради - вашего решения мы тоже не видим)) Критерии могут быть самые разные. Использовали вы или нет транзакции, использовали вы или нет блоки try/catch. Взяли курсор или избыточный FULL JOIN. Или наполнили код IF ELSE , а хотелось одним запросом... Но как ответил Сергей - Один случай действительно не показателен. Продолжайте искать.
UPD: Оглядел поверхностно ваш код и в целом понимаю заказчика. Грехов хватает.
set @flag_item	= (select [1] from #tmp_insert where [0] = @i)
set @flag_in	= (select [2] from #tmp_insert where [0] = @i)
set @flag_out	= (select [3] from #tmp_insert where [0] = @i)
set @flag_count	= (select [4] from #tmp_insert where [0] = @i)

За такое мой руководитель меня распнет и оставит на солнце голгофы.
SELECT @flag_item = col1, @flag_in=col2,@flag_out=col3, @flag_count=col4 FROM #tmp
WHERE col0 = @i

В 4 раза меньше запросов на одной инструкции , а про неподдерживаемые и нечитаемые поля я вообще лучше промолчу.

Кстати - вы откатываете транзакцию при определенных условиях. А что за транзакция? нету риска что вы откатите некую параллельную нормально функционирующую?
Ответ написан
@Noob_001 Автор вопроса
А теперь все одной процедурой и без временных таблиц как хотели многие :) ...

IF OBJECT_ID ( '_data_look', 'P' ) IS NOT NULL 
    DROP PROCEDURE _data_look;
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE _data_look (@item int,@item_in int,@item_out int,@v int,@x nvarchar(max))
AS 
BEGIN
if @x = 'движение'
	if 	(@item_in <> @item_out) and (@item_in + @item_out > 0) and (@v >= 0)
	begin
	DECLARE @follow	int
	SET @follow = 	(
						case 
							when @item_in = 0 and  @item_out > 0 then  1
							when @item_in > 0 and  @item_out = 0 then -1
							when @item_in > 0 and  @item_out > 0 then  0
						end
					)
		if @follow = 1
				if (select SUM(Количество) from _Размещение where Место = @item_out) is null
					begin
					BEGIN  TRANSACTION;
						insert into _Движение   values (@item,@item_in,@item_out,@v)
						insert into _Размещение values (@item,@item_out,@v)
					COMMIT TRANSACTION;		
					end
				else
					begin
					BEGIN  TRANSACTION;
						insert into _Движение   values (@item,@item_in,@item_out,@v)
						update _Размещение
						set Количество = Количество + @v
						where Место = @item_out
					COMMIT TRANSACTION;	
					end
			if @follow = -1
				if (select SUM(Количество) from _Размещение where Место = @item_in) is null return;
				else
				begin
					if (select Количество  - @v from _Размещение where Место = @item_in) < 0 return;
					BEGIN  TRANSACTION;
						insert into _Движение   values (@item,@item_in,@item_out,@v)
						update _Размещение
						set Количество = Количество - @v
						where Место = @item_in
					COMMIT TRANSACTION;	
				end
			if @follow = 0
				if (select SUM(Количество) from _Размещение where Место = @item_in) is null or (select Количество - @v from _Размещение where Место = @item_in) < 0  return;
				else
				begin
				if (select SUM(Количество) from _Размещение where Место = @item_out) is null 
					begin 
					BEGIN  TRANSACTION;
					insert into _Размещение values (@item,@item_out,0)	
					COMMIT TRANSACTION;	
					end
				BEGIN  TRANSACTION;
					insert into _Движение   values (@item,@item_in,@item_out,@v)
					update _Размещение
						set Количество = Количество - @v
						where Место = @item_in
					update _Размещение
						set Количество = Количество + @v
						where Место = @item_out
				COMMIT TRANSACTION;		
				end			
	end
	else 
		return;
if @x = 'изменение'
	begin

		BEGIN  TRANSACTION;
		
		update _Движение
		set Количество = @v
		where	Товар		= @item		and
				Откуда		= @item_in	and
				Куда		= @item_out
		
		
		update _Размещение
		set Количество = 
			(select case when sum(Количество) is null then 0 else sum(Количество) end from _Движение where Куда =  @item_out)
			-
			(select case when sum(Количество) is null then 0 else sum(Количество) end from _Движение where Откуда =  @item_in)
		where Место = @item_out 
		
		COMMIT TRANSACTION;	
	end
if @x = 'снести N'
begin

		BEGIN  TRANSACTION;
		
		delete from _Движение
		where 
				Товар		= @item		and
				(
                                 Откуда		= @item_out	
                                 or  
                                 Куда		= @item_out
                                 )
				
		delete from _Размещение
		where 
				Товар		= @item		and
				Место		= @item_out


		COMMIT TRANSACTION;	
	end	
END
GO

/*=================================*/
/*=================================*/

/* собственно психи одиночки, а можно в цикле + табличка */
exec _data_look 1, 0, 3, 10,   'движение'
exec _data_look 1, 0, 2, 5,     'движение'
exec _data_look 1, 2, 3, 5,     'движение'
exec _data_look 1, 0, 3, 100, 'изменение'   
 /* а тут меняем данные первого exec на 100 и пересчитываем результат, 
но тут на отрицательное не ставил условие- забил :) */
exec _data_look 1, 2, 3, 4,  'снести N'
/* сносим вообще всю историю со складом 3 */

select * from _Движение
select * from _Размещение
/*
truncate table _Движение
truncate table _Размещение
*/
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы