Гость
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / ABC анализ в sql / 25 сообщений из 27, страница 1 из 2
23.01.2012, 17:15
    #37627463
PlanB
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Добрый день!

Подскажите, пожалуйста, возможно ли сделать ABC-анализ запросом.
Краткое пояснение про ABC-анализ: одно из применений закона Парето 80/20.
Задаес две границы для определения зоны B. В данном примере (см. таблицу 1) это 80 и 95% от общего колличества. Весь крупняк по общей сумме меньший, чем 80% итога сносится в группу А.

Таблица1
NAMESUMABC_RAT|PROCPROC_SUMНаименование 115 429 930А|16%16%Наименование 213 497 652А|14%29%Наименование 312 796 790А|13%42%Наименование 412 209 909А|12%55%Наименование 512 022 677А|12%67%Наименование 611 529 588А|12%79%Наименование 710 942 376В|11%90%Наименование 87 166 437С|7%97%Наименование 92 730 968С|3%100%ИТОГО98 326 327X|100%200%*поля PROC и PROC_SUM - вспомогательные, для наглядности.

Спасибо!
...
Рейтинг: 0 / 0
23.01.2012, 19:19
    #37627784
Knyazev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
declare @t table ( name char(1), val int )
insert into @t
values (1,	15429930),(2,	13497652),(3,	12796790),
(4,	12209909), (5,	12022677), (6,	11529588),
(7,	10942376), (8,	7166437), (9,	2730968)

select name, val
     , cast( val*1./a * 100 as decimal(10,2) ) [percent]
     , cast( b*1./a * 100 as decimal(10,2) ) [percent_sum], 
case 
when cast( b*1./a * 100 as decimal(10,2) )  between 0 and 80 then 'A'
when cast( b*1./a * 100 as decimal(10,2) )  > 95 then 'C'
else 'B' end [ABC]
from @t t
cross apply ( select sum(val) a from @t) t1
cross apply ( select sum(val) b from @t where val >= t.val ) t2
...
Рейтинг: 0 / 0
23.01.2012, 21:26
    #37627908
andrey odegov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
declare @t table ( name char(1), val int )
insert into @t
values (1, 15429930), (2, 13497652), (3, 12796790)
     , (4, 12209909), (5, 12022677), (6, 11529588)
     , (7, 10942376), (8, 7166437), (9, 2730968);
select a.name, a.val, 100. * a.val / sum(a.val) over() as pct
     , 100. * sum(b.val) / sum(a.val) over() as run_pct
     , case
       when 100. * sum(b.val) / sum(a.val) over() > 95 then 'C'
       when 100. * sum(b.val) / sum(a.val) over() > 80 then 'B'
       else 'A' end as abc
from @t as a, @t as b
where b.val >= a.val
group by a.name, a.val, a.val;
...
Рейтинг: 0 / 0
24.01.2012, 09:41
    #37628311
PlanB
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
andrey odegov, спасибо большое!
...
Рейтинг: 0 / 0
24.01.2012, 10:14
    #37628342
Дедушка
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
PlanB,
и на каких у вас это объёмах данных?
...
Рейтинг: 0 / 0
24.01.2012, 10:38
    #37628384
PlanB
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
ДедушкаPlanB,
и на каких у вас это объёмах данных?не много, порядка 1000 строк
...
Рейтинг: 0 / 0
08.05.2012, 13:54
    #37785997
ybuivovk
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
andrey odegov,
Здравствуйте Андрей!
У меня проблема запросом для ABC анализа.....не получается вывести накопительный %....я не знаю как уж его сделать...
вот пример кода:

declare @a int
declare @t table ( name int, sum_pokup int, Dolia int)

SELECT DISTINCT @a = sum(REWARD_TRNX_DETAIL.VOLUME_VALUE)
FROM
LOYALTY.REWARD_TRNX
LEFT OUTER JOIN LOYALTY.REWARD_TRNX_DETAIL
ON REWARD_TRNX_DETAIL.TRNX_ID = REWARD_TRNX.TRNX_ID
LEFT OUTER JOIN NODE.NODE
ON REWARD_TRNX.SYSTEM_NODE_ID = NODE.SYSTEM_NODE_ID

INSERT INTO @t
SELECT DISTINCT name = NODE.SYSTEM_NODE_ID --AS name
, sum_pokup = sum(REWARD_TRNX_DETAIL.VOLUME_VALUE) --AS sum_pokup
, Dolia = 100.* sum(REWARD_TRNX_DETAIL.VOLUME_VALUE) / @a --AS Dolia
FROM
LOYALTY.REWARD_TRNX
LEFT OUTER JOIN LOYALTY.REWARD_TRNX_DETAIL
ON REWARD_TRNX_DETAIL.TRNX_ID = REWARD_TRNX.TRNX_ID
LEFT OUTER JOIN NODE.NODE
ON REWARD_TRNX.SYSTEM_NODE_ID = NODE.SYSTEM_NODE_ID
WHERE
REWARD_TRNX.SYSTEM_NODE_ID IS NOT NULL
GROUP BY
NODE.SYSTEM_NODE_ID

SELECT DISTINCT b.name
, b.sum_pokup
, b.Dolia
-- , d.sum_pokup / b.sum_pokup AS Nakop_dolia ----вот эта сумма не правильно выводитсяююю

FROM
LOYALTY.REWARD_TRNX
LEFT OUTER JOIN LOYALTY.REWARD_TRNX_DETAIL
ON REWARD_TRNX_DETAIL.TRNX_ID = REWARD_TRNX.TRNX_ID
LEFT OUTER JOIN NODE.NODE
ON REWARD_TRNX.SYSTEM_NODE_ID = NODE.SYSTEM_NODE_ID
, @t AS b, @t AS d
WHERE
d.sum_pokup >= b.sum_pokup
AND REWARD_TRNX.SYSTEM_NODE_ID IS NOT NULL

GROUP BY
b.name
, b.sum_pokup
, b.Dolia
--, d.sum_pokup / b.sum_pokup ---накопительный процент

ORDER BY
b.sum_pokup DESC
...
Рейтинг: 0 / 0
08.05.2012, 13:55
    #37785999
ybuivovk
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Если кто-то поможет, с меня причитается...честное слово!!!Я на все согласен, чтобы сделать эту хрень....
...
Рейтинг: 0 / 0
08.05.2012, 19:34
    #37786352
aleks2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
ybuivovk
Код: sql
1.
2.
3.
4.
5.
6.
7.
SELECT DISTINCT @a = sum(REWARD_TRNX_DETAIL.VOLUME_VALUE)
FROM
  LOYALTY.REWARD_TRNX
  LEFT OUTER JOIN LOYALTY.REWARD_TRNX_DETAIL
    ON REWARD_TRNX_DETAIL.TRNX_ID = REWARD_TRNX.TRNX_ID
  LEFT OUTER JOIN NODE.NODE
    ON REWARD_TRNX.SYSTEM_NODE_ID = NODE.SYSTEM_NODE_ID




Поведай нам сакральный смысл DISTINCT в энтом запросе.
...
Рейтинг: 0 / 0
10.05.2012, 17:15
    #37788220
ybuivovk
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
aleks2,
Да это я так...скопировал с конструктора....
Я уже сделал ABC анализ по аналогии

declare @t table ( name char(1), val int )
insert into @t
values (1, 15429930), (2, 13497652), (3, 12796790)
, (4, 12209909), (5, 12022677), (6, 11529588)
, (7, 10942376), (8, 7166437), (9, 2730968);
select a.name, a.val, 100. * a.val / sum(a.val) over() as pct
, 100. * sum(b.val) / sum(a.val) over() as run_pct
, case
when 100. * sum(b.val) / sum(a.val) over() > 95 then 'C'
when 100. * sum(b.val) / sum(a.val) over() > 80 then 'B'
else 'A' end as abc
from @t as a, @t as b
where b.val >= a.val
group by a.name, a.val, a.val;

но дело в том, что.... допустим есть 2 одинаковых числа, то накопительный % тобишь " 100. * sum(b.val) / sum(a.val) over() as run_pct " не правильно считает. Он не суммирует процент....:( Как исправить не подскажете?
...
Рейтинг: 0 / 0
10.05.2012, 19:30
    #37788393
sqlinbox
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
ybuivovk,

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
declare @t table ( name char(1), val int )
insert into @t
values
(1, 15429930),
(2, 13497652),
(3, 12796790),
(4, 12209909),
(5, 12209909),
--(5, 12022677),  сделал 2 одинаковых значения
(6, 11529588),
(7, 10942376),
(8,  7166437),
(9,  2730968);

-- ваш вариант

select
a.name,
a.val,
100. * a.val / sum(a.val) over() as pct,
100. * sum(b.val) / sum(a.val) over() as run_pct,
case
when 100. * sum(b.val ) / sum(a.val) over() > 95 then 'C'
when 100. * sum(b.val ) / sum(a.val) over() > 80 then 'B'
else 'A' end as abc
from @t as a
full outer join @t b on 2>1
where b.val >= a.val
group by a.name, a.val
ORDER BY a.name DESC

-- исправленный вариант

declare @t2 table ( name char(1), val int, sm  Int)
insert into @t2
select name, val , 0
from @t order by val desc, name
declare @sm int = 0
update @t2 set @sm = @sm + val, sm = @sm from @t2

select
a.name,
a.val,
100. * a.val / @sm as pct,
100. * a.sm / @sm as run_pct,
case
when 100. * a.sm / @sm > 95 then 'C'
when 100. * a.sm / @sm > 80 then 'B'
else 'A' end as abc
from @t2 as a
order by 100. * a.sm / @sm desc
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
03.03.2016, 13:15
    #39184825
Mike_Gl
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Добрый !
Хочу апнуть темку, поднятую автором поста.
Для одного сплошного уровня, как в его примере, всё работает идеально.

Но в жизни необходимо считать АВС по группам, видам и т.п.
Бьюсь пару дней уже сам, но как-то не хватает объемного зрения и опыта, чтобы также в одном запросе решить эту задачку.
Исходный вариант от автора (уменьшил порядок чисел для наглядности):
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
declare @t table ( id int, val int )
	insert into @t
	values (1, 154), (2, 134), (3, 127)
		 , (4, 122), (5, 120), (6, 115)
		 , (7, 82), (8, 71), (9, 27);

	select 
		a.id, 
		a.val, 
		100. * a.val / sum(a.val) over() as pct
		 , 100. * sum(b.val) / sum(a.val) over() as run_pct
		 , case
		   when 100. * sum(b.val) / sum(a.val) over() > 95 then 'C'
		   when 100. * sum(b.val) / sum(a.val) over() > 80 then 'B'
		   else 'A' end as abc
	from @t as a, @t as b
	where b.val >= a.val
	group by a.id, a.val
	order by a.val desc



Давайте добавим в эту таблицу группы : PID = Parent ID, код родительской папки
Разбил все числа на две группы, по очереди, 1 / 2
и наша цель - посчитать АВС для каждой группы отдельно

Код: sql
1.
2.
3.
4.
5.
declare @t table ( id int, PID int, val int )
insert into @t
values (1, 1, 154), (2, 2, 134), (3, 1, 127)
     , (4, 2, 122), (5, 1, 120), (6, 2, 115)
     , (7, 1, 82), (8, 2, 71), (9, 1, 27);



При попытке сделать аналогично первому решению - в одном запросе - получается какая-то ерунда.
Даже не хочу выкладывать свои попытки.
Вот и прошу уважаемых форумчан помочь и посоветовать, как лучше рассчитать АВС-категории с учетом разбивки на группы.

Есть мысль пойти через врем.таблицу, куда в цикле размещать одну группу , т.е. приводить к 1му варианту или через CTE ...
В идеале нужно применять этот механизм для 3х- 4х вложенных групп (например, Фабрика-Группа-Коллекция).
Т.е. нужно посчитать, какую категорию будет иметь товар в каждом уровне вложения.
...
Рейтинг: 0 / 0
03.03.2016, 13:58
    #39184906
msLex
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Mike_Gl,

да вроде ничего сложного, просто добавить группировку по соответствующему полю

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
declare @t table ( id int, PID int, val int )
insert into @t
values (1, 1, 154), (2, 2, 134), (3, 1, 127)
     , (4, 2, 122), (5, 1, 120), (6, 2, 115)
     , (7, 1, 82), (8, 2, 71), (9, 1, 27);


select a.id, a.PID, a.val, 100. * a.val / sum(a.val) over(partition by a.PID) as pct
     , 100. * sum(b.val) / sum(a.val) over(partition by a.PID) as run_pct
     , case
       when 100. * sum(b.val) / sum(a.val) over(partition by a.PID) > 95 then 'C'
       when 100. * sum(b.val) / sum(a.val) over(partition by a.PID) > 80 then 'B'
       else 'A' end as abc
from @t as a
inner join @t as b on a.PID = b.PID
where b.val >= a.val
group by a.id, a.val, a.val, a.PID;
...
Рейтинг: 0 / 0
03.03.2016, 15:39
    #39185085
Mike_Gl
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
msLexMike_Gl,

да вроде ничего сложного, просто добавить группировку по соответствующему полю


и правда работает
а я добавлял partition везде.. и в sum(b.val) тоже делал over(). Получается каша.
Спасибо большое!

А сам я что-то видимо не догоняю, не вижу, как оно должно работать :-(
...
Рейтинг: 0 / 0
03.03.2016, 15:41
    #39185086
Mike_Gl
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
msLexMike_Gl,
Код: sql
1.
2.
3.
 
....
group by a.id, a.val, a.val, a.PID;



А зачем здесь два раза a.val ?
...
Рейтинг: 0 / 0
03.03.2016, 16:27
    #39185168
a_voronin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Mike_Gl,

Зачем тут вообще JOIN

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
declare @t table ( id int, PID int, val int )
insert into @t
values (1, 1, 154), (2, 2, 134), (3, 1, 127)
     , (4, 2, 122), (5, 1, 120), (6, 2, 115)
     , (7, 1, 82), (8, 2, 71), (9, 1, 27);

SELECT A.* ,100. * pct / run_pct,
	case
	when 100. * pct / run_pct < 55 then 'C'
	when 100. * pct / run_pct < 85 then 'B'
	else 'A' end as abc
FROM 
(
	select id, PID, val, sum(a.val) over(partition by a.PID ORDER BY val ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as pct
		 , sum(a.val) over(partition by a.PID) as run_pct
	from @t as a
) A
ORDER BY PID, val DESC 
...
Рейтинг: 0 / 0
03.03.2016, 16:38
    #39185179
Mike_Gl
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
a_voroninMike_Gl,

Зачем тут вообще JOIN

Код: sql
1.
2.
3.
	(select id, PID, val, sum(a.val) over(partition by a.PID ORDER BY val ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as pct
) A
ORDER BY PID, val DESC 


Вау!
Такая конструкция для меня в новинку. Пошел читать мсдн.

А ответы получаются разные.
Идея примерно понятна, но надо разобраться, почему....
...
Рейтинг: 0 / 0
03.03.2016, 16:41
    #39185183
a_voronin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Mike_Gl,

Я проценты другие поставил , потому что все в C падало
...
Рейтинг: 0 / 0
03.03.2016, 17:26
    #39185249
msLex
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Mike_GlmsLexMike_Gl,
Код: sql
1.
2.
3.
 
....
group by a.id, a.val, a.val, a.PID;



А зачем здесь два раза a.val ?
х/з, я взял исходный запрос и просто добавил группировку
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
04.05.2021, 17:25
    #40068389
gerzzog
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Добрый день,
Спасибо за направление в решении вопроса АВС. Подскажите с одной проблемой
У меня есть рабочий код на вычисление АВС по двум критериям (названия магазина - market_id; название отдела - dep_code).
Мне нужно добавить еще фильтр по дате - название столбца date_start. Но если я его добавляю, пишет Invalid column name 'date_start'. Как добавить в этот код еще фильтр по дате?


drop table if exists #data
select good_id, dep_code, market_id,
qty = SUM(tsell_qty),
amt = SUM(tsell_amt),
buy = SUM(tbuy_amt)

into #data
from finance_agent
where date_start between '20210101' and '20210401'

group by market_id, dep_code, good_id

SELECT s.*,
per = 100. * cumtotal / nullif(s.total,0),
abc = case
when 100. * cumtotal / nullif(s.total,0) = Null then 'C'
when 100. * cumtotal / nullif(s.total,0) < 95 then 'C'
when 100. * cumtotal / nullif(s.total,0) < 80 then 'B'
else 'A' end
FROM
(
select good_id, dep_code, market_id, qty, amt, buy,
cumtotal = sum(s.amt) over (partition by dep_code, market_id order by amt rows between unbounded preceding and current row),
total = sum(s.amt) over (partition by dep_code, market_id)
from #data s
) S
order by dep_code, market_id desc
...
Рейтинг: 0 / 0
04.05.2021, 18:01
    #40068397
Владислав Колосов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
gerzzog,

скорее всего, таблица #data на момент выполнения существует и у нее другой набор столбцов. Замените имя таблицы #data в этом запросе на более сложное или выполняйте drop table в отдельном пакете.
...
Рейтинг: 0 / 0
05.05.2021, 08:11
    #40068480
gerzzog
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Владислав Колосов,
Попробовал изменить название - не помогло.
А вот drop table в отдельном пакете это для меня новое. Можете, пожалуйста, помочь с написанием кода.
Я в этом деле новичок, с предыдущим кодом мне помогли, а внести такое изменение сам не могу(
...
Рейтинг: 0 / 0
05.05.2021, 10:38
    #40068506
aleks222
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Страдалец, тепузики фсе в отпуску. Надо выражопываться отчетливее.

gerzzog
Добрый день,
Мне нужно добавить еще фильтр по дате - название столбца date_start. Но если я его добавляю, пишет Invalid column name 'date_start'. Как добавить в этот код еще фильтр по дате?

drop table if exists #data
select good_id, dep_code, market_id,
qty = SUM(tsell_qty),
amt = SUM(tsell_amt),
buy = SUM(tbuy_amt)

into #data
from finance_agent
-- ЗДЕСЬ ЧТОЛИ? ---------------------------------------
where date_start between '20210101' and '20210401'
-------------------------------------------------------------
group by market_id, dep_code, good_id



У тебя в таблице
finance_agent
есть поле
date_start?

Нету его у тебя там. Вот сервер и возмущается.
...
Рейтинг: 0 / 0
05.05.2021, 11:10
    #40068517
gerzzog
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
есть там такое поле. В том то и дело.
То есть сейчас этот запрос работает. И он выделяет данные по команде where date_start between '20210101' and '20210401'
Но, если я захочу выбрать определенный период и еще добавить фильтр по этому столбцу, по аналогии с market_id, dep_code,
то он мне выкидывает эту ошибку.
Я даже пробовал добавить фильтр АВС не по дате, а по другой колонке из этой базы данных (например импортные поставщики) и он
тоже ругается Invalid column name
...
Рейтинг: 0 / 0
05.05.2021, 11:32
    #40068524
gerzzog
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ABC анализ в sql
Вот даже для интереса попробовал изменить фильтр отдела (dep_code) на дополнительный фильтр, который не работает date_start.
И оно заработало. Но если добавляю опять же туда же dep_code третьим ранжиром, то ругается Invalid column name.
В общем не хочет он работать с любым третьим фильтром.
Может, действительно, нужно выполнить drop table в отдельном пакете. Как это реализовать?
...
Рейтинг: 0 / 0
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / ABC анализ в sql / 25 сообщений из 27, страница 1 из 2
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]