Переключение на Главную Страницу Страницы: 1 ОтправитьПечать
Обычная тема Рассчитанный регистр такое возможно ? (число прочтений - 3066 )
ev-kov
God Member
*****
Отсутствует



Сообщений: 694
Зарегистрирован: 27. Декабря 2006
Пол: Мужской
Рассчитанный регистр такое возможно ?
31. Июля 2007 :: 06:40
Печать  
Как можно получить из регистра остатков таблицу с колонками вида

измерение1,
...
измерениеn,
Документ,
РассчитанныйОстатокПоДокумент.

Привожу абстрактный пример:
есть регистр Взаиморасчеты со структурой
Код
Выбрать все
Измерения:
   Контрагент
Ресурсы
  Сумма 


В таблице движений всего 6 строк:
Контрагент, №Дока, СуммаДока
Петров        Док №1            100      
Петров        Док №2            -200
Петров        Док №3            125
Иванов        Док №1            200
Иванов        Док №2            -300
Иванов        Док №3            155

Выходная таблица должна быть в данном случае
Петров        Док №1            100      100
Петров        Док №2            -200      -100
Петров        Док №3            125      25
Иванов        Док №1            200      200
Иванов        Док №2            -300      -100
Иванов        Док №3            155      55

В 4 колонке рассчитан остаток ПО документ






 

  

Информация - то, что снижает неопределенность в какой-либо области и очень важно не ошибиться областью в наш информационный век!
Наверх
 
IP записан
 
kiruha
1c++ power user
Отсутствует



Сообщений: 1249
Зарегистрирован: 11. Апреля 2007
Re: Рассчитанный регистр такое возможно ?
Ответ #1 - 01. Августа 2007 :: 07:20
Печать  
А в чем проблема?
В регистре есть поле IDDOC - можешь соединиться с журналом.
В журнале - дата/время (для ДБФ и SQL поля разные).
Тебе нужен отбор по дату/время твоего документа.
  
Наверх
 
IP записан
 
ADirks
1c++ developer
1c++ moderator
Отсутствует


А нужны ли мы нам?

Сообщений: 692
Местоположение: Новосибирск
Зарегистрирован: 22. Мая 2006
Пол: Мужской
Re: Рассчитанный регистр такое возможно ?
Ответ #2 - 01. Августа 2007 :: 07:50
Печать  
Где-то на sql.ru находил тему про то, как сделать FIFO чисто декларативным способом.  Ссылку на топик почему-то не сохранил, но финальный запрос есть.
Код
Выбрать все
set nocount on

if object_id('tempdb..#Supplies') is not null drop table #Supplies

create table #Supplies (id int identity, dat smalldatetime, amount smallmoney)

insert #Supplies (dat, amount) values ('2002-09-01', 1000)
insert #Supplies (dat, amount) values ('2002-09-03', 800)
insert #Supplies (dat, amount) values ('2002-09-05', 1400)
insert #Supplies (dat, amount) values ('2002-09-05', 700)



if object_id('tempdb..#Payments') is not null drop table #Payments

create table #Payments (id int identity, dat smalldatetime, amount smallmoney)

--insert #Payments (dat, amount) values ('2002-08-05', 1000)
--insert #Payments (dat, amount) values ('2002-08-05', 300)
insert #Payments (dat, amount) values ('2002-09-01', 600)
--insert #Payments (dat, amount) values ('2002-09-02', 900)
insert #Payments (dat, amount) values ('2002-09-02', 1700)
insert #Payments (dat, amount) values ('2002-09-04', 1300)
insert #Payments (dat, amount) values ('2002-09-05', 100)


if object_id('tempdb..#t1') is not null drop table #t1

select
	a.id,
	a.sum1,
	(a.tot_sum1 - a.sum1) as tot_sum1,
	b.dat
into #t1
from
	(
		select
			a.id,
			max(a.amount) as sum1,
			sum(isnull(b.amount, 0.00)) +  max(a.amount) as tot_sum1
		from
			#supplies a
			left outer join #supplies b on b.id < a.id
		group by a.id
	) as a
	inner join #supplies b on b.id = a.id


if object_id('tempdb..#t2') is not null drop table #t2

select a.id, a.sum2, (a.tot_sum2 - a.sum2) as tot_sum2, b.dat into #t2 from
(select a.id, max(a.amount) as sum2, sum(isnull(b.amount, 0.00))+max(a.amount) as tot_sum2
	from #payments a
	left outer join #payments b on b.id < a.id
	group by a.id
) as a
inner join #payments b on b.id = a.id


select *
from
	(
	select
		a.id as id_1,
		a.sum1,
		a.tot_sum1,
		b.id as id_2,
		b.sum2,
		b.tot_sum2,

		case
			when a.tot_sum1 > b.tot_sum2 then
				case
					when (b.sum2 - (a.tot_sum1 - b.tot_sum2)) > a.sum1 then a.sum1
					when (b.sum2 - (a.tot_sum1 - b.tot_sum2)) <= a.sum1 then b.sum2 - (a.tot_sum1 - b.tot_sum2)
				end
			when a.tot_sum1 < b.tot_sum2 then
				case
					when ((b.tot_sum2 + b.sum2) - a.tot_sum1) >= a.sum1 then (a.sum1 - (b.tot_sum2 - a.tot_sum1))
					when ((b.tot_sum2 + b.sum2) - a.tot_sum1) < a.sum1 then b.sum2
				end
			else
				case
					when a.sum1 > b.sum2 then b.sum2
					when a.sum1 <= b.sum2 then a.sum1
				end
		end x

	from
		#t1 a
		cross join #t2 b
	) as a
where
	x > 0
order by
	a.id_1, a.id_2


select * from #t1
--select * from #t2
select * from #Supplies
select * from #Payments 


Это конечно демо-пример, и под реальные цели его надо переделывать. Но идея интересная.  Сам бы я до такого ни в жисть бы не додумался  Улыбка
А обычно мы считаем такие остатки уже на клиенте, например в момент вывода в отчёт.
  
Наверх
 
IP записан
 
ev-kov
God Member
*****
Отсутствует



Сообщений: 694
Зарегистрирован: 27. Декабря 2006
Пол: Мужской
Re: Рассчитанный регистр такое возможно ?
Ответ #3 - 01. Августа 2007 :: 10:26
Печать  
ADirks писал(а) 01. Августа 2007 :: 07:50:
Где-то на sql.ru находил тему про то, как сделать FIFO чисто декларативным способом.  Ссылку на топик почему-то не сохранил, но финальный запрос есть.


Мутный запрос, без поллитры трудно разобраться, но опять же cross join, у Хендерсона есть подобный пример, пробовал работает. А представь если надо регистр рассчитать на 2500 контрагентов и каждый их док движения, ну скажем в среднем доков по 15, итого на 37500 документов и НА ВСЁ ЭТО CROSS JOIN - сервер вообще выживет - это первый вопрос.
Дальше, можно реализовать расчет регистра по каждому контру (также как и 1-м варианте через cross join нагрузка на скуль будет мелкими запросами, а не одним большим как в 1-м варианте ) отдельно и юзать режимRPC. Меня волнует вопрос будет ли ЗНАЧИТЕЛЬНЫМ выигрыш в скорости в 1 варианте по сравненинию со вторым вариантом, стоит ли заморачиваться ?
  

Информация - то, что снижает неопределенность в какой-либо области и очень важно не ошибиться областью в наш информационный век!
Наверх
 
IP записан
 
ADirks
1c++ developer
1c++ moderator
Отсутствует


А нужны ли мы нам?

Сообщений: 692
Местоположение: Новосибирск
Зарегистрирован: 22. Мая 2006
Пол: Мужской
Re: Рассчитанный регистр такое возможно ?
Ответ #4 - 01. Августа 2007 :: 10:57
Печать  
Да, запрос конечно мутный, и таки да - crossjoin. 
Я лично не проверял это вариант в боевых условиях, и соответственно меня тоже волнует вопрос, а будет ли выигрыш? Точнее, когда лучше использовать вариант 1, а когда 2.  Теоретически понятно, что чем меньше исходная выборка, тем предпочтительнее декларативный вариант, но где граница?
  
Наверх
 
IP записан
 
ev-kov
God Member
*****
Отсутствует



Сообщений: 694
Зарегистрирован: 27. Декабря 2006
Пол: Мужской
Re: Рассчитанный регистр такое возможно ?
Ответ #5 - 31. Августа 2007 :: 11:02
Печать  
Роясь в статьях нашел простой алгоритм релизующий тему, надо слегка подправить, а запрос получается очень простой без использования cross join

Нарастающие итоги в запросах SQL Server

Arthur Fuller (оригинал: Running totals in SQL Server queries)
Перевод Моисеенко С.И.


Вам поручают создать запрос в SQL Server, содержащий нарастающие итоги на момент наступления события. Классическим примером является счет в банке.

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

Листинг А

Код
Выбрать все
CREATE TABLE [dbo].[BankAccount](
    [TransactionID] [int] IDENTITY(1,1) NOT NULL,
     [TransactionDateTime] [datetime] NOT NULL CONSTRAINT [DF_BankAccount_TransactionDateTime] DEFAULT(getdate()),
     [Amount] [money] NOT NULL CONSTRAINT [DF_BankAccount_Amount] DEFAULT((0)),
     [TransactionType] [char](1)COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
     [AccountNumber] [varchar](50)COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT [PK_BankAccount] PRIMARY KEY CLUSTERED
(
     [TransactionID] ASC
)WITH (PAD_INDEX =OFF, IGNORE_DUP_KEY =OFF) ON [PRIMARY]
) ON [PRIMARY]
 



Вот типичные строки:

1     2006-11-03 02:33:42.340     10000.00
2     2006-11-03 02:34:50.467    -500.00
3     2006-11-03 02:35:04.857     250.00
4     2006-11-03 02:42:19.763    -124.25
Так как дата имеет значение по умолчанию, все, что Вы должны сделать, - это только добавить несколько сумм. Для простоты в примере приводится информация только об одном банковском счете.

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

Следующий запрос реализует этот алгоритм:

Код
Выбрать все
SELECT transactionid, transactiondatetime, amount,
        (SELECT SUM(amount)
        FROM dbo.bankaccount as D1
        WHERE D1.transactiondatetime <= D0.transactiondatetime) AS balance
FROM dbo.bankaccount AS D0
 



В результате получим следующий набор строк:

1      2006-11-03 02:33:42.340     10000.00      10000.00
2      2006-11-03 02:34:50.467    -500.00      9500.00
3      2006-11-03 02:35:04.857     250.00     9750.00
4      2006-11-03 02:42:19.763    -124.25     9625.75

Как показывает этот пример, нарастающие итоги легко получить, если вы понимаете, что от вас требуется. В данном примере предполагается, что таблица содержит только один счет, но легко обобщить его на случай со многими счетами: Вам нужно лишь добавить в таблицу еще столбец с номером счета - BankAccountNumber, а в запросе в предикате предложения WHERE указать нужный счет.

Вы можете также преобразовать этот пример, чтобы получить нарастающие разности (как в инвентарных счетах). Вы начинаете с описи 1 000, и затем вычитаете различные расходы и поступления.

Такие запросы имеют два важных преимущества:
· Вам не потребуется хранить результаты. При отборе по номеру счета или подобного ему внешнему ключу запрос будет выполняться очень быстро.
· Упрощается работа с журналом транзакций, который может просматриваться построчно. Если возникает ошибка, то Вы будете в состоянии изолировать конкретную транзакцию, которая ее вызвала.
  

Информация - то, что снижает неопределенность в какой-либо области и очень важно не ошибиться областью в наш информационный век!
Наверх
 
IP записан
 
Переключение на Главную Страницу Страницы: 1
ОтправитьПечать