Программирование на SQL | Задача по выборке данных

В этом разделе сайта попытаемся разобраться с программированием баз данных. Язык называется SQL. В этом языке нет или почти нет классов, переменных, массивов и циклов. Сравнивать его с языками высокого уровня не имеет смысла. Но без него Вы не сможете написать интерфейс для настольных приложений Windows или интернет сайтов. Для Разработчика надо обязательно надо знать SQL, библиотеки обработки данных на C#, Microsoft Visual Studio, Microsoft SQL Server Management Studio или dbForge Studio for SQL Server

Задача по выборке данных

Целью данной задачи является создание запроса или процедуры для изучения ваших знаний SQL Server. Задача не совсем простая и решений может быть несколько. Если Вы претендуете на вакансию Разработчика SQL Server, то Вам будет дано на решение не более 3 дней

Необходимо написать скрипт, который выводит таблицу, в которой для каждого клиента указана следующая информация
1. Наименование клиента
2. ИНН клиента
3. № счета, по которому есть открытая поставка (действующая на дату 01.01.2021) по продукту «Продукт А».
Если есть несколько счетов, удовлетворяющие данному условию, необходимо вывести тот счет, по которому создана
открытая поставка по «Продукт А» с максимальной датой окончания. Если нет счетов, удовлетворяющих данному условию,
необходимо вывести счет с максимальной датой оплаты, в котором есть строки на «Продукт А» на подключение или продление.
Не более одного счета на клиента
4. Дата создания счета из п.3
5. Дата оплаты счета из п.3
6. Сумма счета по всем строкам из п.3
7. Оплата по счету по всем строкам из п.3

Примечания:
● У каждого счета должна быть хотя бы одна строка счета;
● По каждой строке счета может быть создано любое количество поставок, а может не быть ни одной;
● У клиента может быть несколько параллельных поставок по одному продукту.
● Cost и Paid указывается за суммарное количество продуктов/услуг в строке счета, т.е. стоимость 1 шт. из строки счета = Cost/Cnt.

Таблицы для решения

--создание объектов
--Клиенты
create table dbo.Clients (
  cID   int           not null
 ,Name  nvarchar(500) collate Cyrillic_General_CI_AS not null
 ,Inn   nvarchar(12)  collate Cyrillic_General_CI_AS not null
 ,Phone nvarchar(15)  collate Cyrillic_General_CI_AS null
 ,Email nvarchar(500) collate Cyrillic_General_CI_AS null
);
alter table dbo.Clients add constraint PK_Clients primary key clustered (cID);

--Счета
create table dbo.Bills (
  bID     int          not null
 ,Num     nvarchar(50) collate Cyrillic_General_CI_AS not null
 ,BDate   date         not null
 ,PayDate date         null
 ,cID     int          not null
);
alter table dbo.Bills add constraint PK_Bills primary key clustered (bID);
alter table dbo.Bills add constraint FK_Bills_cID foreign key (cID) references dbo.Clients (cID);

--Строки счета
create table dbo.BillContent (
  bcID        int            not null
 ,bID         int            not null
 ,Product     nvarchar(50)   collate Cyrillic_General_CI_AS null
 ,TariffName  nvarchar(1000) collate Cyrillic_General_CI_AS null
 ,ServiceName nvarchar(1000) collate Cyrillic_General_CI_AS null
 ,TypeID      tinyint        not null
 ,Cost        money          not null
 ,Paid        money          null
 ,Cnt         int            not null
);
alter table dbo.BillContent add constraint PK_BillContent primary key clustered (bcID);
alter table dbo.BillContent add constraint FK_BillContent_bID foreign key (bID) references dbo.Bills (bID);

--Поставки
create table dbo.RetailPacks (
  rpID  int  not null
 ,bcID  int  not null
 ,Since date not null
 ,UpTo  date not null
);
alter table dbo.RetailPacks add constraint PK_RetailPacks primary key clustered (rpID);
alter table dbo.RetailPacks add constraint FK_RetailPacks_bcID foreign key (bcID) references dbo.BillContent (bcID);

--Ответ
create table #Answer (
  Name    nvarchar(500) collate Cyrillic_General_CI_AS null
 ,Inn     nvarchar(12)  collate Cyrillic_General_CI_AS not null
 ,Num     nvarchar(50)  collate Cyrillic_General_CI_AS null
 ,BDate   date          null
 ,PayDate date          null
 ,BillSum money         null
 ,BillPay money         null
);

 

Решение задачи

Предлагаемое решение содержит процедуру, и небольшую ошибку, которую Вы должны исправить сами. Таблицы тоже заполните сами. Таким образом,  это позволит Вам понять хорошо ли Вы разбираетесь в этой теме и сможете ли находить и решать различные проблемы в  SQL Server. Важно. Желательно Вам с нуля написать решение или план данной задачи, а не просто почитать готовое решение

-- Запуск процедуры
EXEC TestSQLServer_SP '2021-01-01T00:00:00','Продукт А',0

-- Тесты --
EXEC TestSQLServer_SP 
EXEC TestSQLServer_SP '2020-09-16T00:00:00',NULL

 

ALTER PROCEDURE [dbo].[TestSQLServer_SP] 
	@DateP as DateTime = '2021-01-01',
	@Product as nvarchar(512) = NULL,
	@TEST as int = 1
AS
BEGIN

	SET NOCOUNT ON;

	-- Создадим временную таблицу для упрощения вычислений и тестирования
	SELECT c.cID, b.bID, c.Name, c.Inn, b.Num, b.BDate, b.PayDate, bc.Cost, bc.Paid, bc.Product, bc.Cnt, rp.Since, rp.UpTo, 
	CASE
		WHEN  @DateP between rp.Since AND rp.UpTo THEN rp.UpTo
		ELSE NULL
	END	
	as UpToDate 
	INTO #Clients FROM Clients c
		LEFT JOIN Bills b ON c.cID = b.cID
		    LEFT JOIN BillContent bc ON bc.bID = b.bID 
				LEFT JOIN RetailPacks rp ON bc.bcID = rp.bcID
					WHERE bc.Product = ISNULL(@Product, bc.Product)

	-- Получаем результат
	;WITH CTE AS
	( SELECT *, RN = ROW_NUMBER() OVER (PARTITION BY cID ORDER BY UpToDate DESC, PayDate DESC)
	  FROM #Clients
	)
	SELECT c.[Name], c.Inn, c.Num, c.BDate, c.PayDate, Sum(c.Cost) as SumCost, Sum(Paid) as SumPaid FROM CTE c WHERE c.RN=1 GROUP BY 
		c.[Name], c.Inn, c.Num, c.BDate, c.PayDate 

	-- Тестирование --
	IF @TEST = 1
	BEGIN
		SELECT 'OK' as 'Test', *,RN = ROW_NUMBER() OVER (PARTITION BY cID ORDER BY UpToDate DESC, PayDate DESC) FROM #Clients
	END

 

Добавить комментарий

Loading