Как разделить два значения из одного столбца в SQL
как говорится в заголовке, я хотел бы разделить два значения друг с другом, которые находятся в одном столбце. Е. Г.
A B C D
Shirts 2011 85 0
Shirts 2012 92 percent change from 2011 to 2012
Shirts 2013 100 percent change from 2012 to 2013
Pants 2011 31 0
Pants 2012 42 percent change from 2011 to 2012
Pants 2013 55 percent change from 2012 to 2013
Jacket 2011 10 0
Jacket 2012 16 percent change from 2011 to 2012
Jacket 2013 18 percent change from 2012 to 2013
в этом примере столбец D будет производным от столбца C, где значение 2012 вычитается из 2011, а затем умножается на 100, чтобы получить процент.
Я не знаю, как настроить запрос я попытался сделать кучу подзапросов, но не знал, как связать их вместе. Любая помощь будет очень признательна.
7 ответов
вот вариант, чтобы получить то, что вы после
SELECT t1.a, t1.b, t1.c,
CASE WHEN t2.c IS NULL THEN 0 ELSE t1.c - t2.c END AS d,
CASE WHEN t2.c IS NULL THEN 0 ELSE (1.0 * t1.c - t2.c) / t1.c * 100.0 END AS pct
FROM t t1
LEFT OUTER JOIN t t2 ON t1.a = t2.a
AND t1.b = t2.b + 1
вы можете выполнить это с помощью self-join:
SELECT curr.ClothingType, curr.SalesYear, curr.NumberSold
, COALESCE((CAST((curr.NumberSold - prev.NumberSold) AS NUMERIC(5,2)) / prev.NumberSold) * 100, 0) AS PercentChange
FROM #Clothes AS curr
LEFT JOIN #Clothes AS prev ON curr.ClothingType = prev.ClothingType
AND curr.SalesYear = prev.SalesYear + 1
если я правильно понимаю ваши требования, вы можете использовать рекурсивный cte для достижения ваших результатов. Это использует ROW_NUMBER()
и разделы по (группам по) столбцу A.
этот метод лучше всего работает, если вы не можете гарантировать последовательные годы в столбце B. Если у вас всегда есть последовательные годы, то bobs предоставляет лучшую альтернативу.
with cte as (
select A, B, C,
ROW_NUMBER() OVER (PARTITION BY A ORDER BY B) rn
from yourtable
),
recursive_cte as (
select A, B, C, 0 prc
from cte
where rn = 1
union all
select y.A, y.B, y.C, y.C-c.C prc
from cte y
join cte c on y.a=c.a and y.rn=c.rn+1
)
select *
from recursive_cte
order by a, b
это вернет разницу между каждым год и предыдущий сгруппированы по столбцу A. Он использует 2-й CTE только для простоты. Если вы хотите изменить фактический процент, обновите приведенную выше формулу.
--EDIT
поскольку похоже, что вы ищете процентный рост, попробуйте заменить y.К-с. C КНР с этой формулой вместо:
cast(y.C as decimal(10,2))/cast(c.C as decimal(10,2))
использовать CAST
Если типы данных-целые числа.
Я согласен с Шиваном, но только потому, что я не знаю, как это сделать без PHP. С PHP это просто вопрос вытягивания двух итогов, выполнения математики и отправки запроса с ответами.
ТАКЖЕ ОБЯЗАТЕЛЬНО ПРОЧИТАЙТЕ ЭТО, ПОТОМУ ЧТО ЭТО БОЛЕЕ ВАЖНАЯ ЧАСТЬ
Твоя математика ошибочна. (Shirts2011 - Shirts2012) * 100
не дает вам процентное изменение. Это просто дает вам 100 times the difference of the two
(на самом деле, отрицательная разница, основанная на вашей формулировке). Что вы хотите, math-wise, есть:
((Item2012-Item2011)/Item2011)*100
Я знаю, что внешние родители не нужны, но они облегчают чтение. Процентное изменение такое же, как и 100-кратное отношение разности двух к первоначальному.
отредактировано для добавления PHP-кода.
PHP выглядит грубо, но он выполняет свою работу.
$conn = new PDO(HOST:DATABASE, USERNAME, PASSWORD);
$query = "SELECT A, B, C FROM yourTable";
$st = $conn->prepare($query);
$st->execute();
$list = array();
while($row = $st->fetch(PDO::FETCH_ASSOC))
$list[] = $row;
$fill = array();
for($i=1; $i<count($list); $i++)
if($list[$i]['A'] == $list[$i-1][A])
$fill[] = $array('A' => $list[$i]['A'],
'B' => $list[$i]['B'],
'D' => ($list[$i]['C']-$list[$i-1]['C'])/$list[$i-1]['C']*100);
$update = new PDO(HOST:DATABASE, USERNAME, PASSWORD);
for($i=0; $i<count($fill); $i++){
$query = "UPDATE yourTable SET D = " . $fill[$i]['D'] . " WHERE A = " . $fill[$i]['A'] . " AND B = " . $fill[$i]['B'];
$st = $update->prepare($query);
$st->execute();
}
просто инициализируйте таблицу, где столбцы 2011 D = 0.
UPDATE yourTable SET D = 0 WHERE B = 2011;
и прежде чем пламя начнется, я знаю, что foreach работал; я просто думаю, что стандарт выглядит лучше (и позволяет пропустить первое значение 2011).
попробуйте это:
SELECT t1.type A, t1.year B, t1.value C,
IF(
EXISTS(
SELECT 1 FROM table t2 WHERE t1.type = t2.type AND t1.year = (t2.year - 1)
),
((SELECT t3.year FROM table t3 WHERE t1.type = t3.type AND t1.year = (t3.year - 1)) - t1.year)/t1.year,
0
) D
FROM table t1
не очень эффективно, но это можно сделать.
вы можете попробовать это тоже:
UPDATE mytable t1
INNER JOIN mytable t2
ON t1.A = t2.A AND t2.B = t1.B - 1
SET t1.D = ((t1.C - t2.C) / t2.C) * 100;
посмотреть скрипка.
предполагая, что у вас уже есть 0 по умолчанию для D. Если нет, просто установите его в 0 для всех строк перед запуском этого запроса.
попробуйте это:
select Y2013.*, Y2012.C, Y2013.C, Y2013.C/Y2011.C
from (
select * from data where B = year(getdate())
) Y2013
left join (
select * from data where B = year(getdate()) - 1
) Y2012 on Y2012.A = Y2013.A
left join (
select * from data where B = year(getdate()) - 2
) Y2011 on Y2011.A = Y2012.A
and Y2011.A = Y2013.A