Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Работа Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Стандартные требования на вакансию SQL junior dev  [new]
Troi51
Member

Откуда:
Сообщений: 10
Модератор: Вынесено из https://www.sql.ru/forum/1333789


zorrocool,

Здравствуйте.

Я не так давно начал плотно изучать SQL и сопутствующие ему технологии (в частности, остановился на MS SQL Server). Имеется большое желание перерасти из "что-то там умею" в полноценного джуниора с последующим трудоустройством и развитием. Но возникла проблема с определением набора навыков и направлением развития. Спрашивал на форуме, но особо пользы это не принесло, и из-за этого решил спрашивать точечно.
Поэтому хотел бы у Вас уточнить, как у полноценного работодателя:
1. У Вас в требованиях указаны "основные принципы проектирования реляционных баз данных (нормальные формы)". Какие НФ необходимо знать (и понимать, само собой), что бы соискатель удовлетворял предъявляемым требованиям?
2. Что Вы вкладываете в понятие "понимать принципы работы с индексами" ? Достаточно ли будет знать принцип работы индекса или нужны более глубокие познания?

Понимаю, что требования разнятся от вакансии к вакансии, но хотелось бы услышать именно Вашу точку зрения.

Прошу прощения, что не по теме и не в личку, но мало ли найдется ещё новичок, который будет по крупицам собирать полезную информацию.

Сообщение было отредактировано: 29 мар 21, 12:58
23 мар 21, 19:10    [22299069]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
godsql
Member

Откуда:
Сообщений: 180
Troi51,

По моему личному мнению, все эти " (нормальные формы)". Какие НФ необходимо знать (и понимать, само собой), что бы соискатель удовлетворял предъявляемым требованиям?" представляют чисто академический интерес для показа образованности.
В реальности, в лучшем случае, вы столкнетесь с принципами "достаточной избыточности", а в худшем - "тихий ужас", где поклонник принципов нормализации повесится сразу, только взглянув на это изделие :)
23 мар 21, 20:28    [22299095]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
DaniilSeryi
Member

Откуда:
Сообщений: 1844
Troi51, выкиньте из требований zorrocool оптимизацию запросов, секционирование и опыт работы с системами контроля версий - вполне приличный джуниор на пол-пути к миддлу, а то и миддл получится.

Ну, и по мелочи надо будет знать:
что такое dml и ddl;
про разницу между типами varchar и char, а также varchar и nvarchar;
и что такое ntext, и где хранятся значения поля такого типа;
что такое статистика в SQL Server;
про разные виды индексов, включая кластерные, некластерные, фильтрованные индексы и не фильтрованные, с ключом из одного поля и из нескольких, с included-полями и без, что такое покрывающие индексы и что такое columnstore индексы, и т.д.;
про максимальную длину ключа индекса;
сколько может быть кластерных индексов на таблицу и почему;
и сколько может быть некластерных индексов на таблицу;
что такое scan и seek;
разницу между ограничениями primary key и unique не забывать;
вообще знать про constraint-ы всякие, включая default;
быть в курсе про вычисляемые столбцы, и чем обычные вычисляемые столбцы отличаются от постоянных (persisted);
быть в курсе про типы recovery model базы данных;
суметь ответить на вопрос о типах функций;
и суметь ответить на вопрос о том, как передать в функцию таблицу;
помнить про разницу между табличной переменной, временной таблицей и постоянной временной таблицей;
не путать delete, drop и truncate table;
знать, что на самом деле update - это delete с insert-ом;
быть в курсе про разные уровни выполнения триггеров, знать типы триггеров, и помнить про логон-триггеры;
также быть в курсе, когда именно имеет смысл создавать триггеры, а когда не стоит;
поработать с курсором хотя бы раз;
поработать с common table expression;
поработать с регрессиями с использованием common table expression;
ответить, чем отличается where от having;
ответить, в чём разница между count(*), count(ИмяПоля) и count(distinct ИмяПоля).
и т.д.

Про уровни изоляции транзакций и типы и уровни блокировок - это уже сильно позже.
Про секционирование (партиционирование) - тоже сильно позже.

Про высшее шаманство, как сделать, чтобы табличное представление ВСЕГДА возвращало отсортированный набор данных - это не спросят.

Сообщение было отредактировано: 23 мар 21, 20:37
23 мар 21, 20:35    [22299097]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
DaniilSeryi
Member

Откуда:
Сообщений: 1844
godsql
Troi51,

По моему личному мнению, все эти " (нормальные формы)". Какие НФ необходимо знать (и понимать, само собой), что бы соискатель удовлетворял предъявляемым требованиям?" представляют чисто академический интерес для показа образованности.
В реальности, в лучшем случае, вы столкнетесь с принципами "достаточной избыточности", а в худшем - "тихий ужас", где поклонник принципов нормализации повесится сразу, только взглянув на это изделие :)


Джун должен их помнить, а миддл и выше - уметь применять автоматически.
23 мар 21, 20:40    [22299100]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
DaniilSeryi
Member

Откуда:
Сообщений: 1844
А... Про типы соединений забыл... Для джуниора - надо знать inner, cross и outer join (left, right, full), а также outer apply.

А вот hash, merge и loop join - это уже совсем другая вещь - её надо знать уже миддлу и выше.

Сообщение было отредактировано: 23 мар 21, 20:43
23 мар 21, 20:50    [22299103]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
Troi51
Member

Откуда:
Сообщений: 10
DaniilSeryi,

Огромное Вам человеческое спасибо за столь подробный и обстоятельный ответ! Я не ожидал даже, честно говоря. Буду изучать и постигать, благо в документации и примерах использования я недостатка на текущий момент не встречал.
23 мар 21, 22:14    [22299131]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
DaniilSeryi
Member

Откуда:
Сообщений: 1844
Troi51,

Завтра набросаю примеры задач, которые могут давать на собеседованиях.
23 мар 21, 23:04    [22299154]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
Troi51
Member

Откуда:
Сообщений: 10
DaniilSeryi,

Добрый день. Прошу прощения за беспокойство, но не могли бы всё таки набросать примеров? Вектор развития, обозначенный Вами до этого, очень помогает сейчас, к слову.
27 мар 21, 10:04    [22300687]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
DaniilSeryi
Member

Откуда:
Сообщений: 1844
Для разминки вот эти семь. Обратите внимание - в пунктах 1 и 2 Вы должны дать ответ, не выполняя код. Потом запустите код и проверьте. Если сможете объяснить, почему именно получился тот результат, что получился - ещё лучше.

1) Что вернет запрос при последовательном выполнении команд?

create table tab1
(
	id int not null,
	val int
);

select 'abc' from tab1
union
select 'abc' from tab1
union all
select 'abcdefg' from tab1;



2) Что вернут запросы?

create table tab1
(
	id int not null,
	val int
);
insert into tab1 (id, val) values (1, 1);
insert into tab1 (id, val) values (2, 2);
insert into tab1 (id, val) values (3, 3);
insert into tab1 (id, val) values (4, null);

select count(*), count(id), count(val), max(val) from tab1;
select * from tab1 where val in (select val from tab1);
select * from tab1 where val not in (select val from tab1);



3) Написать запрос, который выведет значения всех полей таблицы по условию:
Для каждого id_parent выбирать только первые 3 id, отсортированные по убыванию.
Если для id_parent не набирается 3х id, то такие случаи не выводить
table tab2
(
	id int not null,
	id_parent int
);



4) Написать запрос, который выводит список id, у которых кол-во значений val:
- равных 3 больше 10 штук
- или равных 4 больше 5 штук
table tab1
(
	id int not null,
	val int
);



5)
table tab_department --Справочник департаментов
(
	id_dep int not null,
	dep_name varchar(100) not null
);

table tab_empl --Справочник сотрудников
(
	id_emp int not null,
	fio varchar(100) not null,
	id_dep int, --ИД департамента
	id_emp_manager int, --ИД руководителя
	lvl int not null-- уровень
);

Написать запрос, который вернет список департаментов и кол-во работающих там тех сотрудников, у которых нет руководителя или его руководитель выше 10 уровня


6)
table tab1
(
	id int GENERATED BY DEFAULT AS IDENTITY not null,
	val int not null
);

table tab2
(
	id int not null,
	val_src int
);

table tab3
(
	id int not null,
	val_src int
);


В таблицу tab1 в поле val необходимо загрузить значения val_src из таблиц tab2 и tab3.
Написать скрипт, который вставит только те значения val_src, которых еще не было в таблице tab1


7)
table tab_empl --Справочник сотрудников
(
	id_emp int not null,
	fio varchar(100) not null,
	id_dep int, --ИД департамента
	id_emp_manager int, --ИД руководителя
	grade int not null-- уровень
);


Для всех сотрудников проставить уровень, как уровень его руководителя минус 1. Если у сотрудника нет руководителя, то оставить уровень неизменным

Сообщение было отредактировано: 27 мар 21, 20:05
27 мар 21, 20:05    [22300880]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
DaniilSeryi
Member

Откуда:
Сообщений: 1844
Из более сложного вот такое - но это уже для уверенного миддла, как мне кажется. Для одной из задач есть подсказка - там может помочь алгоритм "Острова" / Islands.
Также четвёртая задача из перечня требует генерации данных, которая может занять до нескольких часов. В случае с ней можете ограничиться ответом на вопрос про индексы.

+
SET NOCOUNT ON
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
create database Exam_Open
go
use Exam_Open
go
--/*
IF OBJECT_ID('[TestDoc].[Accounts]') IS NOT NULL
  DROP TABLE [TestDoc].[Accounts]

IF OBJECT_ID('[TestDoc].[Contracts]') IS NOT NULL
  DROP TABLE [TestDoc].[Contracts]
--*/
--------------------------------------------------------------------------------------
-- Структура данных                                                                 --
--------------------------------------------------------------------------------------
IF SCHEMA_ID('TestDoc') IS NULL
  EXEC('
    CREATE SCHEMA [TestDoc]
  ')
GO

IF OBJECT_ID('[TestDoc].[Contracts]') IS NULL
  -- Договора
  CREATE TABLE [TestDoc].[Contracts]
  (
    [Id]        Int           NOT NULL  IDENTITY(1,1),
    [DocNo]     NVarChar(50)  NOT NULL,
    [DateFrom]  Date          NOT NULL, --  Дата, когда договор начал действовать
    [DateTo]    Date              NULL, --  Дата, когда договор прекращает действовать (последний день действия договора); NULL = бесконечность
    -- ... И еще какие-то поля
    PRIMARY KEY CLUSTERED([Id])
  )
GO

IF OBJECT_ID('[TestDoc].[Accounts]') IS NULL
  -- Счета
  CREATE TABLE [TestDoc].[Accounts]
  (
    [Id]            Int           NOT NULL  IDENTITY(1,1),
    [Contract_Id]   Int           NOT NULL, -- Договор, в рамках которого счет заключен
    [Number]        NVarChar(50)  NOT NULL, -- Номер счета
    [DateTimeFrom]  DateTime      NOT NULL, -- Момент времени (дата+время!), когда счет начал действовать
    [DateTimeTo]    DateTime          NULL, -- Момент времени (дата+время!), когда счет прекратил действовать
    -- ... И еще какие-то поля
    PRIMARY KEY CLUSTERED([Id]),
    FOREIGN KEY ([Contract_Id]) REFERENCES [TestDoc].[Contracts] ([Id])
  )
GO

/*
-----------------------------------------------------
Задача 1. 
-----------------------------------------------------
Напишите скрипт, который вернет список "ошибок" в учетной системе.
Под "ошибкой" подразумевается ситуация, когда счет действует (действовал), а договор, в рамках которого заключен счет, не действует (не действовал).
--*/

set nocount on
set ansi_nulls on
set quoted_identifier on
go

--/*
------------------------------------------------------------------
-- Создание структуры
------------------------------------------------------------------
if schema_id('Test') is null
  exec('create schema [Test]')
go

if object_id('[Test].[Contracts]') is null
  create table [Test].[Contracts]
  (
    [Id]          int   not null identity(1,1),
    [Type_Id]     int   not null,
    [Client_Id]   int   not null,
    [DateFrom]    date  not null,
    [DateTo]      date      null,
    primary key clustered ([Id])
  )
go

/*


-----------------------------------------------------
Задача 2. Версия: v08
-----------------------------------------------------
Напишите скрипт, который вернет список всех не пересекающихся и несмежных периодов
(т.е., между двумя периодами должен быть минимум один «пустой» день) между
@DateBegin и @DateEnd включительно, когда у клиента был хотя бы один активный договор типа @Type_Id.
Учесть, что у клиента может быть несколько действующих договоров.

Результат должен быть представлен в следующем виде:
-- Client_Id        -- Клиент
-- First_Date       -- Дата начала непрерывного периода действия договора(-ов) заданного типа
-- Last_Date        -- Дата окончания непрерывного периода действия договора(-ов) заданного типа

--*/
set nocount on
set ansi_nulls on
set quoted_identifier on
go

--/*
------------------------------------------------------------------
-- Создание структуры
------------------------------------------------------------------
if schema_id('TestCars') is null
  exec('create schema [TestCars]')
go

if object_id('[TestCars].[Points]') is null
  -- Точки
  create table [TestCars].[Points]
  (
    [Id]          int     not null identity(1,1),
    [Type_Id]     char(1) not null,               -- тип точки: D = Склад; S = Магазин
    primary key clustered ([Id]),
    check ([Type_Id] in ('D', 'S'))
  )
go

if object_id('[TestCars].[Cars]') is null
  -- Машины
  create table [TestCars].[Cars]
  (
    [Id]          int     not null identity(1,1),
    [Capacity]    int     not null,               -- Грузоподьемность
    primary key clustered ([Id])
  )
go

if object_id('[TestCars].[Routes]') is null
  -- Машины
  create table [TestCars].[Routes]
  (
    [Id]            int       not null identity(1,1),
    [Point_Id]      int       not null,
    [Car_Id]        int       not null,
    [Load]          int       not null,               -- Изменение загрузки авто при посещении данной точки. +N = в авто дозагрузили N кг; -N = из машины выгрузили N кг
                                                      -- При этом в магазине точка разгружается, а при посещении склада загружается/дозагружается
    [ArrivalTime]   datetime  not null,
    [DepartureTime] datetime  not null,
    primary key clustered ([Id]),
    foreign key ([Point_Id]) references [TestCars].[Points] ([Id]),
    foreign key ([Car_Id]) references [TestCars].[Cars] ([Id])
  )
go


/*
ВНИМАНИЕ! В начале скрипта-решения в комментариях укажите, пожалуйста, Ваши ФИО.

-----------------------------------------------------
Задача 3. Версия: v08
-----------------------------------------------------
В течение дня машина совершает несколько поездок. Каждая поездка начинается с загрузки машины на складе.
Далее машина посещает несколько магазинов, в каждом из которых частично разгружается.
Затем машина может прибыть на один из складов, дозагрузиться и начать следующий маршрут.
Каждый маршрут всегда проезжается в течение одного календарного дня (нет маршрутов с началом и концом в разных днях).
Машина движется всегда с одной и той же скоростью, скорости разных машин могут отличаться.
По одному и тому же маршруту может проехать несколько различных машин.

Надо 
1. найти топ-3 неэффективных маршрутов и топ-3 неэффективных машин по каждому из критериев:
1.1. Недозагруженность машины, т.е. отношение «загрузка машины/грузоподъемность» после выезда со склада в начале маршрута
1.2. Размер остатка в машине после посещения всех магазинов на маршруте
2. Найти самую быструю машину или доказать, что по представленным данным это невозможно сделать.


SET NOCOUNT ON
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO

--/*
IF OBJECT_ID('[TestMoney].[Operations]') IS NOT NULL
  DROP TABLE [TestMoney].[Operations]

IF OBJECT_ID('[TestMoney].[Currencies Rates]') IS NOT NULL
  DROP TABLE [TestMoney].[Currencies Rates]

IF OBJECT_ID('[TestMoney].[Currencies]') IS NOT NULL
  DROP TABLE [TestMoney].[Currencies]

IF OBJECT_ID('[TestMoney].[Clients]') IS NOT NULL
  DROP TABLE [TestMoney].[Clients]
--*/
--------------------------------------------------------------------------------------
-- Структура данных                                                                 --
-- (*) исключительно для тестирования, не претендует на реальность и адекватность   --
--------------------------------------------------------------------------------------
IF SCHEMA_ID('TestMoney') IS NULL
  EXEC('
    CREATE SCHEMA [TestMoney]
  ')
GO

IF OBJECT_ID('[TestMoney].[Clients]') IS NULL
  CREATE TABLE [TestMoney].[Clients]
  (
    [Id]        Int                                   NOT NULL  IDENTITY(1,1),
    [Name]      NVarChar(128)                         NOT NULL,
    -- ... И еще какие-то поля
    PRIMARY KEY CLUSTERED([Id])
  )
GO
IF OBJECT_ID('[TestMoney].[Currencies]') IS NULL
  CREATE TABLE [TestMoney].[Currencies]
  (
    [Id]        Int                                   NOT NULL,
    [CodeLat3]  Char(3) COLLATE Cyrillic_General_BIN  NOT NULL,
    [Name]      NVarChar(128)                         NOT NULL,
    PRIMARY KEY CLUSTERED([Id])
  )
GO
IF OBJECT_ID('[TestMoney].[Currencies Rates]') IS NULL
  CREATE TABLE [TestMoney].[Currencies Rates]
  (
    [Currency_Id]       Int           NOT NULL, -- Валюту, курс которой указан
    [BaseCurrency_Id]   Int           NOT NULL, -- Базовая валюта; для пары USD/RUB в поле ВaseCurrency_Id будет ссылка на RUB; в поле Currency_Id - ссылка на USD; в поле Rate = курс = 60; т.е. 60 RUB = 1 USD
    [Date]              Date          NOT NULL, -- Дата курса
    [Rate]              Numeric(32,8) NOT NULL, -- Собственно курс 
    [Volume]            Numeric(18,8) NOT NULL, -- За количество; Например, за 10 000 Белорусских рублей дают 39.4419 Рублей; Rate = 39.4419; Volume = 10 000;
    PRIMARY KEY CLUSTERED([Currency_Id], [BaseCurrency_Id], [Date]),
    FOREIGN KEY ([Currency_Id]) REFERENCES [TestMoney].[Currencies] ([Id]),
    FOREIGN KEY ([BaseCurrency_Id]) REFERENCES [TestMoney].[Currencies] ([Id])
  )
-- Чтобы получить сумму Sb в @BaseCurrency_Id, если у Вас есть сумма Sc в валюте Currency_Id,
-- то надо найти на интересующую дату такую ближайшую по дате запись (курс есть не на каждый день),
-- где [BaseCurrency_Id] = @BaseCurrency_Id и [Currency_Id] = @Currency_Id и [Date] <= @Date,
-- умножить на Rate и разделить на Volume
-- т.е. Sb = Sc * Rate / Volume на требуемую дату
GO

IF OBJECT_ID('[TestMoney].[Operations]') IS NULL
  CREATE TABLE [TestMoney].[Operations]
  (
    [Id]                Int           NOT NULL IDENTITY(1,1),
    [Date]              Date          NOT NULL,               -- Дата операции
    [Client_Id]         Int           NOT NULL,               -- Клиент, по которому меняется баланс
    [Value]             Numeric(32,8) NOT NULL,               -- Сумма, на которую меняется баланс
    [Currency_Id]       Int           NOT NULL,               -- Валюта операции
    [DocNo]             NVarChar(32)      NULL,
    -- ... И еще какие-то поля
    PRIMARY KEY CLUSTERED([Id]),
    FOREIGN KEY ([Currency_Id]) REFERENCES [TestMoney].[Currencies] ([Id]),
    FOREIGN KEY ([Client_Id]) REFERENCES [TestMoney].[Clients] ([Id])
  )
GO

----------------------------------------------------
-- Генерация данных
-----------------------------------------------------
/*
TRUNCATE TABLE [TestMoney].[Operations]
TRUNCATE TABLE [TestMoney].[Currencies Rates]

DELETE FROM [TestMoney].[Currencies]
DELETE FROM [TestMoney].[Clients]
--*/
GO
--/*
INSERT INTO [TestMoney].[Clients] ([Name])
SELECT
  [Name]    = CAST(O1.[object_id] AS NVarChar(128)) + ' - ' + CAST(O2.[object_id] AS NVarChar(128))
FROM
(
  SELECT TOP (100)
    O.[object_id]
  FROM sys.all_objects O
) O1
CROSS APPLY
(
  SELECT TOP (20)
    O.[object_id]
  FROM sys.all_objects O
) O2
GO

INSERT INTO [TestMoney].[Currencies]
VALUES
  (1, 'RUB', 'Рубль'),
  (2, 'USD', 'Доллар США'),
  (3, 'EUR', 'Евро'),
  (4, 'JPY', 'Йена'),
  (5, 'BYR', 'Белорусский рубль')
GO

DECLARE @DateStart Date = '20130101'
INSERT INTO [TestMoney].[Currencies Rates]
SELECT
  [Currency_Id]     = C.[Id],
  [BaseCurrency_Id] = 1,
  [Date]            = DATEADD(Day, I.[RowNumber], @DateStart),
  [Rate]            = CASE C.[CodeLat3]
                        WHEN 'USD' THEN 40 - 10 + RAND( CAST(CAST(RIGHT(NewId(), 4) AS Binary(4)) AS Int) ) * 20
                        WHEN 'EUR' THEN 50 - 10 + RAND( CAST(CAST(RIGHT(NewId(), 4) AS Binary(4)) AS Int) ) * 20
                        WHEN 'JPY' THEN 40 - 10 + RAND( CAST(CAST(RIGHT(NewId(), 4) AS Binary(4)) AS Int) ) * 20
                        WHEN 'BYR' THEN 35 - 7 + RAND( CAST(CAST(RIGHT(NewId(), 4) AS Binary(4)) AS Int) ) * 15
                      END,
  [Volume]          = CASE
                        WHEN C.[CodeLat3] = 'BYR' THEN 10000
                        WHEN C.[CodeLat3] = 'JPY' THEN 100
                        ELSE 1
                      END
FROM [TestMoney].[Currencies] C
CROSS APPLY
(
  SELECT TOP (365*3)
    [RowNumber]     = ROW_NUMBER() OVER (ORDER BY O1.[object_id], O2.[object_id])
  FROM
  (
    SELECT TOP (100)
      O.[object_id]
    FROM sys.all_objects O
  ) O1
  CROSS APPLY
  (
    SELECT TOP (50)
      O.[object_id]
    FROM sys.all_objects O
  ) O2
) I
WHERE C.[Id] > 1 -- кроме рубля
  AND I.[RowNumber] % 10 > 2 -- чтобы были пробелы в курсах
GO

-- За 3 года 2013, 2014, 2015
-- Учтите, что время заполнения может дойти до 1 часа!
DECLARE
  @DateStart  Date        = '20130101',
  @N          Int         = 12 * 3,
  @DebugTime  DateTime    = GETDATE()

WHILE @N > 0 BEGIN

  INSERT INTO [TestMoney].[Operations] ([Date], [Client_Id], [Value], [Currency_Id], [DocNo])
  SELECT
    [Date]        = DATEADD(Day, I.[RowNumber], @DateStart),
    [Client_Id]   = C.[Id],
    [Value]       = RAND( CAST(CAST(RIGHT(NewId(), 4) AS Binary(4)) AS Int) ) * 1000 - 500,
    [Currency_Id] = CR.[Id],
    [DocNo]       = CAST(C.[Id] AS NVarChar(20)) + N'/' + CAST(CR.[Id] AS NVarChar(20)) + N'/' + CAST(I.[RowNumber] AS NVarChar(20)) + N'-' + CAST(I2.[RowIndex] AS NVarChar(20))
  FROM [TestMoney].[Clients]          C
  CROSS JOIN [TestMoney].[Currencies] CR
  CROSS APPLY
  (
    SELECT TOP (30)
      [RowNumber]     = ROW_NUMBER() OVER (ORDER BY O.[object_id])
    FROM sys.all_objects O
  ) I
  CROSS APPLY
  (
    SELECT TOP (20)
      [RowIndex]      = ROW_NUMBER() OVER (ORDER BY O.[object_id])
    FROM sys.all_objects O
  ) I2

  SET @DateStart = DATEADD(Month, 1, @DateStart)
  SET @N -= 1

END

SELECT [RUN_TIME] = CONVERT(VarChar(20), GETDATE() - @DebugTime, 114)
--*/
GO

/*

-----------------------------------------------------
Задача 4. Версия: v07
-----------------------------------------------------
Напишите скрипт, который вернет обороты по клиентам в следующем виде:
-- Client_Id        -- Клиент
-- Currency_Id      -- Валюта
-- BaseBalance      -- Изменение баланса клиента в базовой валюте = сумма всех операций, у которых Date >= @DateFrom и Date < @DateTo
Порядок вывода данных:
--ORDER BY
--  Client_Id, Currency_Id

При этом входящие параметры:
  @BaseCurrency_Id        - идентификатор базовой валюты, к которой надо привести сумму Balance;
  @DateFrom, @DateTo      - период за который надо расчитать баланс клиента

При написании скрипта предположите, что в таблице [TestMoney].[Currencies Rates] есть курсы для [BaseCurrency_Id] = @BaseCurrency_Id
(т.е. не надо усложнять задачу до кросс-курсов)

Условие: в таблице Operations очень много данных. @DateFrom и @DateTo, как правило, небольшой период (не более 1 недели при общей истории данных в Operations не менее 3-х лет)
Предложите хороший индекс(ы) для данного запроса(ов).

Прокомментируйте/обоснуйте Ваш выбор. Какие были варианты. Почему "да"/"нет"?
--*/
GO

-----------------------------------------------------
-- Пример тестовых параметров:
-----------------------------------------------------

DECLARE
  @DateFrom         Date    = '20150101'
DECLARE
  @DateTo           Date    = DATEADD(Day, 7, @DateFrom),
  @BaseCurrency_Id  Int     = 1


Сообщение было отредактировано: 29 мар 21, 12:59
27 мар 21, 20:26    [22300890]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
DaniilSeryi
Member

Откуда:
Сообщений: 1844
Также на собеседованиях любят спрашивать задачку про удаление дублирующихся строк из таблицы, в которой нет поля ID. Здесь надо использовать оконную функцию Row_number().
Пример таблицы, для которой надо написать запрос на удаление дублей:

CREATE TABLE TEST.C
(
  B VARCHAR(255)
)

INSERT INTO TEST.C(B) VALUES ('AAA');
INSERT INTO TEST.C(B) VALUES ('ABA');
INSERT INTO TEST.C(B) VALUES ('AAB');
INSERT INTO TEST.C(B) VALUES ('ABB');
INSERT INTO TEST.C(B) VALUES ('BBA');
INSERT INTO TEST.C(B) VALUES ('AAA');
INSERT INTO TEST.C(B) VALUES ('AAA');
INSERT INTO TEST.C(B) VALUES ('ABB');
INSERT INTO TEST.C(B) VALUES ('BBA');



Другой вопрос, который многие любят:
--Создайте таблицу
create schema test;
go
CREATE TABLE TEST.A
(
B int
)
;
INSERT INTO TEST.A(B) VALUES (1);
INSERT INTO TEST.A(B) VALUES (NULL);
INSERT INTO TEST.A(B) VALUES (2);
INSERT INTO TEST.A(B) VALUES (3);

--Ответьте, какие результаты вернут запросы к таблице, приведенные ниже?

SELECT * FROM TEST.A;

SELECT * FROM TEST.A WHERE 1 = 1;

SELECT * FROM TEST.A WHERE NULL = '';

SELECT * FROM TEST.A WHERE B != 1;

SELECT * FROM TEST.A WHERE B = B;

SELECT * FROM TEST.A WHERE B NOT IN (1,NULL);

SELECT * FROM TEST.A WHERE B IN (1,NULL);


И ещё один любимый многими вопрос. Могут попросить написать результаты запросов к таблицам, могут попросить подсчитать и сказать число строк, которые вернут запросы:
create schema test;
go
CREATE TABLE TEST.E
(
B int
)
;
INSERT INTO TEST.E(B) VALUES (1);
INSERT INTO TEST.E(B) VALUES (1);
INSERT INTO TEST.E(B) VALUES (NULL);
INSERT INTO TEST.E(B) VALUES (3);
INSERT INTO TEST.E(B) VALUES (4);

CREATE TABLE TEST.F
(
C int
)
;
INSERT INTO TEST.F(C) VALUES (1);
INSERT INTO TEST.F(C) VALUES (NULL);
INSERT INTO TEST.F(C) VALUES (NULL);
INSERT INTO TEST.F(C) VALUES (2);
INSERT INTO TEST.F(C) VALUES (2);
INSERT INTO TEST.F(C) VALUES (4);
INSERT INTO TEST.F(C) VALUES (5);

SELECT * 
FROM TEST.E
INNER JOIN TEST.F ON B=C;

SELECT * 
FROM TEST.E
LEFT JOIN TEST.F ON B=C;

SELECT * 
FROM TEST.E
RIGHT JOIN TEST.F ON B=C;

SELECT * 
FROM TEST.E
FULL JOIN TEST.F ON B=C;

SELECT * 
FROM TEST.E
CROSS JOIN TEST.F;


Сообщение было отредактировано: 27 мар 21, 20:49
27 мар 21, 20:55    [22300903]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
DaniilSeryi
Member

Откуда:
Сообщений: 1844
Ну и ещё одно упражнение. Посмотрите код. Скажите, какие значения вернут запросы select. Почему?

create table dbo.a(id int)
go
create table dbo.a1(id int)
go
create table #b(id int)
go
create table #b1(id int)
go
declare @c table (id int)

begin tran
	insert into dbo.a(id) 
	values(1)

	insert into #b(id) 
	values(2)

	insert into @c(id) 
	values(3)
rollback tran;

select * from dbo.a
select * from #b
select * from @c

declare @c1 table (id int)

begin tran 
	insert into dbo.a1(id)
	values(1)

	insert into #b1(id) 
	values(2)

	insert into @c1(id) 
	values(3)
commit tran;


select * from dbo.a1
select * from #b1
select * from @c1
27 мар 21, 23:13    [22300940]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
monsenior
Member

Откуда: Москва
Сообщений: 893
DaniilSeryi
Также на собеседованиях любят спрашивать задачку про удаление дублирующихся строк из таблицы, в которой нет поля ID. Здесь надо использовать оконную функцию Row_number().


А на совсем правильных собесах спросят почему за использование Row_number() для поиска дублей бьют по рукам))
28 мар 21, 13:18    [22301047]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
DaniilSeryi
Member

Откуда:
Сообщений: 1844
monsenior
DaniilSeryi
Также на собеседованиях любят спрашивать задачку про удаление дублирующихся строк из таблицы, в которой нет поля ID. Здесь надо использовать оконную функцию Row_number().


А на совсем правильных собесах спросят почему за использование Row_number() для поиска дублей бьют по рукам))


Хм... И почему?
И какие тогда есть варианты решения задачи? помимо select distinct - delte - insert и с Row_number ?

Модератор: Тема перенесена из форума "Вакансии".


Сообщение было отредактировано: 29 мар 21, 12:53
28 мар 21, 13:46    [22301055]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
DaniilSeryi
Member

Откуда:
Сообщений: 1844
На самом деле, задача на удаление дублей заточена на знание и умение работать с оконными функциями.
Идёт часто в связке с вопросом, а какие оконные функции Вы знаете?

Сообщение было отредактировано: 28 мар 21, 13:58
28 мар 21, 13:57    [22301061]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
godsql
Member

Откуда:
Сообщений: 180
DaniilSeryi
На самом деле, задача на удаление дублей заточена на знание и умение работать с оконными функциями.
Идёт часто в связке с вопросом, а какие оконные функции Вы знаете?


на самом деле, если есть уникальный ключ/поле, то в дополнительной нумерации необходимости нет.
На куче - да, без row_number не обойдешься
28 мар 21, 15:33    [22301094]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
DaniilSeryi
Member

Откуда:
Сообщений: 1844
godsql
DaniilSeryi
На самом деле, задача на удаление дублей заточена на знание и умение работать с оконными функциями.
Идёт часто в связке с вопросом, а какие оконные функции Вы знаете?


на самом деле, если есть уникальный ключ/поле, то в дополнительной нумерации необходимости нет.
На куче - да, без row_number не обойдешься


Я же в описании задачи указал, что поля ID нету. :-)
28 мар 21, 23:15    [22301212]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
Dmitry_PV
Member

Откуда:
Сообщений: 70
DaniilSeryi, хорошие примеры, благодарю.
29 мар 21, 10:42    [22301300]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
yob
Member

Откуда:
Сообщений: 39
Troi51,
T-sql query
T-sql programming
r-sql perfomance tuning
Msdn
На начало хватит
29 мар 21, 15:03    [22301465]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
yob
Member

Откуда:
Сообщений: 39
yob
Troi51,
T-sql query
T-sql programming
r-sql perfomance tuning
Msdn
На начало хватит

ну еще сборник рецептов завхвати, о райли который
29 мар 21, 15:06    [22301467]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
Ivan Durak
Member

Откуда: Minsk!!!
Сообщений: 3668
godsql
DaniilSeryi
На самом деле, задача на удаление дублей заточена на знание и умение работать с оконными функциями.
Идёт часто в связке с вопросом, а какие оконные функции Вы знаете?


на самом деле, если есть уникальный ключ/поле, то в дополнительной нумерации необходимости нет.
На куче - да, без row_number не обойдешься

ну на нормальных базах эффективнее юзать rowid и ему подобные.
29 мар 21, 15:23    [22301477]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
Ivan Durak
Member

Откуда: Minsk!!!
Сообщений: 3668
но вообще все что касается понимания планов выполнения запросов я от джуниоров не требовал никогда.
Так что даю 95% что оно и не понадобится.
Ну и DBA знания - туда же, не требуются, я никогда не спрашивал,
По моему опыту отсобеседовав порядка 300 кандидатов в джуниоры sql уже хорошо если он может писать запросы с группировкой и having, умеет лефт джоином и иннером пользоваться ну и может модельку в 3нф на 3 таблички нарисовать и m:m свзязь.
Уже энаф, так сказать
29 мар 21, 15:30    [22301486]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
yob
Member

Откуда:
Сообщений: 39
Ivan Durak
но вообще все что касается понимания планов выполнения запросов я от джуниоров не требовал никогда.
Так что даю 95% что оно и не понадобится.
Ну и DBA знания - туда же, не требуются, я никогда не спрашивал,
По моему опыту отсобеседовав порядка 300 кандидатов в джуниоры sql уже хорошо если он может писать запросы с группировкой и having, умеет лефт джоином и иннером пользоваться ну и может модельку в 3нф на 3 таблички нарисовать и m:m свзязь.
Уже энаф, так сказать

Пахнет быстрым рефакторингом кода
29 мар 21, 15:41    [22301499]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
yob
Member

Откуда:
Сообщений: 39
yob
Ivan Durak
но вообще все что касается понимания планов выполнения запросов я от джуниоров не требовал никогда.
Так что даю 95% что оно и не понадобится.
Ну и DBA знания - туда же, не требуются, я никогда не спрашивал,
По моему опыту отсобеседовав порядка 300 кандидатов в джуниоры sql уже хорошо если он может писать запросы с группировкой и having, умеет лефт джоином и иннером пользоваться ну и может модельку в 3нф на 3 таблички нарисовать и m:m свзязь.
Уже энаф, так сказать

Пахнет быстрым рефакторингом кода

хотя хз, смотря какая предметная область, и что требуется в итоге, удтверждать не буду
29 мар 21, 15:48    [22301505]     Ответить | Цитировать Сообщить модератору
 Re: Стандартные требования на вакансию SQL junior dev  [new]
DaniilSeryi
Member

Откуда:
Сообщений: 1844
Не могу удержаться от того, чтобы не выложить.

Нашёл у себя кусочек теории со своими комментариями
Теория, которая нужна… …да никому она на практике не нужна. Честно говоря, у меня это на собеседованиях спросили только один раз. У Вас это спрашивают на собеседовании? Бегите оттуда.

Атрибут — свойство некоторой сущности. Нормальные люди называют это полем или столбцом таблицы.

Домен атрибута — множество допустимых значений, которые может принимать атрибут (значения, которые можно вводить в столбец таблицы).

Кортеж — конечное множество взаимосвязанных допустимых значений атрибутов, которые вместе описывают некоторую сущность (строка таблицы).

Отношение — конечное множество кортежей (таблица).

Схема отношения — конечное множество атрибутов, определяющих некоторую сущность. Иными словами, это структура таблицы, состоящей из конкретного набора полей.

Проекция — отношение, полученное из заданного путём удаления и (или) перестановки некоторых атрибутов.

Функциональная зависимость между атрибутами (множествами атрибутов) X и Y означает, что для любого допустимого набора кортежей в данном отношении: если два кортежа совпадают по значению X, то они совпадают по значению Y. Например, если значение атрибута «Название компании» — Canonical Ltd, то значением атрибута «Штаб-квартира» в таком кортеже всегда будет Millbank Tower, London, United Kingdom. Обозначение: {X} -> {Y}.

Аномалией называется такая ситуация в таблице БД, которая приводит к противоречию в БД либо существенно усложняет обработку БД. Причиной является излишнее дублирование данных в таблице, которое вызывается наличием функциональных зависимостей от не ключевых атрибутов.

Аномалии-модификации проявляются в том, что изменение одних данных может повлечь просмотр всей таблицы и соответствующее изменение некоторых записей таблицы.

Аномалии-удаления — при удалении какого либо кортежа из таблицы может пропасть информация, которая не связана на прямую с удаляемой записью.

Аномалии-добавления возникают, когда информацию в таблицу нельзя поместить, пока она не полная, либо вставка записи требует дополнительного просмотра таблицы.


И чуть больше приближенная к практике теория:
Нормальная форма — требование, предъявляемое к структуре таблиц в теории реляционных баз данных для устранения из базы избыточных функциональных зависимостей между атрибутами (полями таблиц).

Метод нормальных форм (НФ) состоит в сборе информации о объектах решения задачи в рамках одного отношения и последующей декомпозиции этого отношения на несколько взаимосвязанных отношений на основе процедур нормализации отношений.

Цель нормализации: исключить избыточное дублирование данных, которое является причиной аномалий, возникших при добавлении, редактировании и удалении кортежей(строк таблицы).

На самом деле разработчику нормальные формы нужны только для того, чтобы понять и запомнить два простых правила: 1) одна ячейка таблицы – одно значение; 2) для каждого отдельного понятия (сущности) предметной области должна быть выделена своя собственная таблица.
Когда Вы спроектируете под контролем наставника свою первую БД, получите по шее за то, что предлагаете хранить в ячейке таблицы несколько значений и за то, что у Вас нет нужных таблиц-справочников, и Вы дублируете данные о сущностях текстом по всей таблице, тогда Вы намертво усвоите принципы, которые скрываются за формулировками нормальных форм. После этого формулировки нормальных форм Вам будут нужны только на собеседованиях, и то – степень адекватности тех, кто задаёт такие вопросы, вызывает сомнения.
29 мар 21, 21:24    [22301695]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Работа Ответить