Не будем засорять этот раздел разными простыми задачами, нам нужны необычные идеи. Вот, например, такая задача. Она встречается в банках, где стек разработки на SQL достигает 90%. На разработку дается максимум 24 часа (т.е. есть время и другими делами позаниматься). Мне удалось ее решить вечером часа за 3, успев сделать и некоторые домашние дела.
Но это не все, задача не имеет типового решения, всегда есть еще и другие способы. Подумайте над этим. Даю описание.
Задача - написать запрос, выводящий средний остаток из таблицы на заданный период. Для проверки результата вывести средний остаток с 9 янв по 17 янв. Примечание. В банке, в части экономии ресурсов SQL сервера, остатки по счету хранятся не на каждый день, а дифференцировано, когда были проводки. С другой стороны клиенту банка надо знать, какая сумма у него на счете за ЛЮБОЙ день. Исходные данные даны в таблице tblFactAmount ниже.
create table tblFactAmount (fAmount float, dtValueChange date)
;
insert into tblFactAmount (fAmount, dtValueChange)
values
(3, '20210101'),
(5, '20210110'),
(1, '20210114'),
(10,'20210116'),
(2, '20210117')
Вот мое решение. Оформил его в виде SP процедуры. Прежде, чем читать решение, подумайте 5 минут. Это намного интереснее. Вдруг ваше решение окажется лучше ...
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Автор: Виктор Конюков
-- Дата создания: 11.01.2023 18:45
-- Версия: 1.0
-- Email: ...
-- Задача: написать запрос, выводящий средний остаток из таблицы на заданный период.
-- Для проверки результата вывести средний остаток с 9 янв по 17 янв
-- Проверка:
/*
EXEC TestSP '20210109','20210117'
*/
-- =============================================
ALTER PROCEDURE TestSP
@Date1 as DateTime = NULL,
@Date2 as DateTime = NULL
AS
BEGIN
SET NOCOUNT ON;
-- Создаем таблицу
IF OBJECT_ID (N'tblFactAmount', N'U') IS NULL
BEGIN
create table tblFactAmount (fAmount float, dtValueChange date) ;
insert into tblFactAmount (fAmount, dtValueChange)
values
(3, '20210101'),
(5, '20210110'),
(1, '20210114'),
(10,'20210116'),
(2, '20210117') ; -- Лучше пробел поставить
END
--
-- Создаем КАЛЕНДАРЬ с датами на нужный период.
-- Лучше его сохранить во временной таблице
-- Для повышения просизводительности можно добавить уникальный индекс по dtValueChange
--
create table #tblCalendar (dtValueChange date);
DECLARE @i as int
SET @i = 0
WHILE (@i<=DateDiff(d,@Date1,@Date2))
BEGIN
insert into #tblCalendar (dtValueChange)
values ( DATEADD(day, @i, @Date1) ) ;
SET @i = @i + 1
-- Вариант 2. Можно добавить поле для хранения fAmount и заполнить его
END
-- Вариант 1. Исходная выборка за каждый день с 9 янв по 17 янв
SELECT t1.dtValueChange,
(SELECT TOP 1 t2.fAmount FROM tblFactAmount t2
WHERE t2.dtValueChange <= t1.dtValueChange
ORDER BY t2.dtValueChange DESC) as fAmount from #tblCalendar t1
-- Выключено. Проверка значений за период
IF 1 = 2
SELECT * FROM tblFactAmount
ORDER BY dtValueChange
-- Зачистка. Работаем аккуратно, спрячем реальную таблицу от удаления
IF 1 = 2
IF OBJECT_ID (N'tblFactAmount', N'U') IS NOT NULL
DROP TABLE tblFactAmount ;
-- Временная не нужна. Лучше ее удалить принудительно
IF OBJECT_ID (N'#tblCalendar', N'U') IS NOT NULL
DROP TABLE #tblCalendar ;
END
На экране результат в Microsoft SQL Server Management Studio выглядит так.