SQL Multiply values from all previous rows - mysql

Refer to the image above.
I have Table 1, and I want to produce Table 2 with SQL.
The first year has to be set to the value 10. The values following will multiply 10 by the multiplier for that year and previous years in Table 1.
For example:
For 2002, the value will be 10 * 2 (2002 multiplier) * 1 (2001 multiplier) = 20.
For 2005, the value will be 10 * 5 * 3 * 1 * 2 * 1 (all previous year multipliers) = 300.
How would I go about doing this? I'd appreciate any help.

A colleague of mine long ago taught me a trick to solve this kind of problems using logarithm properties.
Basically you can do:
Exp(sum(ln(multiplier)))
Edited after the OP made me realize it was incomplete
To do the cumulative logic you need you should apply this on a self-join
select a.youryear, Exp(sum(ln(b.multiplier))) cumulative_mutiplier
from yourtable as a
join
yourtable as b on a.youryear>=b.youryear
group by a.youryear;
I've prepared a test on rextester
create table yourtable (
youryear integer,
multiplier integer
);
insert into yourtable(youryear,multiplier) values (2000,10);
insert into yourtable(youryear,multiplier) values (2001,1);
insert into yourtable(youryear,multiplier) values (2002,2);
insert into yourtable(youryear,multiplier) values (2003,1);
insert into yourtable(youryear,multiplier) values (2004,3);
insert into yourtable(youryear,multiplier) values (2005,5);
select a.youryear, Exp(sum(ln(b.multiplier))) cumulative_mutiplier
from yourtable as a
join
yourtable as b on a.youryear>=b.youryear
group by a.youryear;
The result is:
youryear cumulative_mutiplier
1 2000 10
2 2001 10
3 2002 20
4 2003 20
5 2004 60
6 2005 300

select year
,x
,#result := #result*coalesce(x,10) as result
from table1,(select #result:=1) i
order by year
;
# year, x, result
2000, , 10
2001, 1, 10
2002, 2, 20
2003, 1, 20
2004, 3, 60
2005, 5, 300

Related

Replace values in column on SQL [duplicate]

This question already has answers here:
Filter rows in a column based on set rules in SQL
(2 answers)
Closed 1 year ago.
Group ID Values Month
1 09239820 43 May
2 2872498938 23 Jan
2 1267 18 Dec
3 23219823983 09 Sept
3 267839236 11 July
4 33287442 23 Jan
I want to replace the 1st, 2nd and 4th numbers in the ID column with letters
Replace 1st with N
Replace 2nd with X
Replace 4TH with D
Expected output:
Group ID Value Month
1 NX2D9820 43 May
2 NX7D498938 23 Jan
2 NX6D 18 Dec
3 NX2D9823983 09 Sept
3 NX7D39236 11 July
4 NX2D7442 23 Jan
I am new to SQL, and I have written the following code below (it is not working)
SELECT * FROM #table# t1;
UPDATE t1 SET ID = CONCAT('NX', SUBSTRING(ID,3,1), 'D', SUBSTRING(ID,5));
SELECT * FROM t1;
I found a way of doing this task, maybe it is not the simplest and fastest one but it make sense. If somebody think of any improvement on the query, feel free to edit my answer.
UPDATE test_01 tbl1
INNER JOIN (
select `group`, concat_ws('',substring(RIGHT((insert(id, 1, 2, 'NX')), 9999),1,3), substring(LEFT((insert(id, 4, 1, 'D')), 9999),4,9999)) as id_tbl2
from test_01)
as tbl2
ON tbl1.`group` = tbl2.`group`
SET tbl1.id = tbl2.id_tbl2;
Working demo:https://www.db-fiddle.com/f/7yUJcuMJPncBBnrExKbzYz/6
Let me explain what the query does
insert(id, 1, 2, 'NX') ---> inserts NX in first and second place
insert(id, 4, 1, 'D' ---> inserts D in the fourth place
substring(RIGHT((insert(id, 1, 2, 'NX')), 9999),1,3) ---> select
first three characters changed
substring(LEFT((insert(id, 4, 1, 'D')), 9999),4,9999) ---> select from the fourth character to the end
of the row because 9999 extends the column limit
Using concat_ws I combine tha changed data to a new table and in the
end we can update using the join condition.

How to determine the next delivery day given this table? SQL

I have this table which lists the delivery days available for an area. Also given are the order date and count of stores with the same order date and delivery day.
CREATE TABLE table1
(`order_date` date, `area` varchar(20), `delivery_days` varchar(20), `stores` int)
;
INSERT INTO table1
(`order_date`, `area`, `delivery_days`, `stores`)
VALUES
('2020-11-22', 'A', '1,3,5', 17),
('2020-11-25', 'A', '1,3,5', 4),
('2020-11-26', 'B', '2,4,6', 9),
('2020-11-28','B', '2,4,6', 6);
You can read the available delivery days as (1 for Mon, 2 for Tue, 3 for Wed... 6 for Sat).
With that said, if stores from area A ordered on 2020-11-22, Sunday, the nearest delivery day is the next day, 1 Monday. And if stores from the same area ordered on 2020-11-25, Wednesday, the nearest delivery day is 2 days from said date, which is 5 Friday.
order_date area delivery_days stores
2020-11-22 A 1,3,5 17
2020-11-25 A 1,3,5 4
2020-11-26 B 2,4,6 9
2020-11-28 B 2,4,6 6
What I would like to do is summarize this information into a table that looks like this-- where each column counts the number of stores that fall into the delivery category then gets the percentage relative to the total count of stores.
area total_stores next_day_delivery percent 2_day_delivery percent 3_day_delivery percent
A 21 17 81 4 19
B 15 9 60 6 40
How can I do this? Here's the sqlfiddle: http://sqlfiddle.com/#!9/784e1/1

Grouping MySQL view in a sequence of rolling dates

I've got two tables:
Table Transmission
------------------------------
Id GroupID Amount Timestamp
1 1 5 2015-05-20 00:00:00
2 1 4 2015-05-19 00:00:00
3 1 10 2015-04-20 00:00:00
4 1 7 2015-04-19 00:00:00
5 1 9 2015-03-20 00:00:00
6 1 2 2015-03-18 00:00:00
Table Group
---------
Id DateCreated BillStart BillStop
1 2015-03-15 2015-05-15 2015-06-14
BillStart and BillStop have a trigger on them that runs daily, if the current Date is greater than BillStop, both BillStart/BillStop increase by a month (so these are effectively the current range we are looking at).
I already have a SQL view that can sum up a range of the transmission entries where the timestamp is between BillStart and BillStop, what I am looking to do is have another view that would effectively hold the sums of transmissions of past months. i.e. if a BillStart/BillStop goes from 2015-05-15 to 2015-06-14, then the view would know to group past transmissions from the ranges of 2015-4-15 to 20-15-14, 2015-3-15 to 2015-4-14, and so on, up until the last range containing the groups creation date.
Ideally the view would look like
-------------------------------------
GroupId Sum BillStart BillStop
1 9 2015-05-15 2015-06-14
1 17 2015-04-15 2015-05-14
1 11 2015-03-15 2015-04-14
Is there a better way to do this?
Another option I was considering was a table for GroupBillRanges that would entail:
GroupBillRange
--------------
Id GroupId BillStart BillStop
1 1 2015-03-15 2015-04-14
2 1 2015-04-15 2015-05-14
3 1 2015-05-15 2015-06-14
And this would be added when each bill range gets updated by the month. With this I would just be able to match all Transmission.GroupId to GroupDateRange.GroupId
Yes, you would need to create the "GroupBillRange" table. Otherwise you lose any record of what the Bill Start/Stop dates were on the old groups. (Sure, you could assume that they are always from the 15th to the 14th. But the one time that they are not, you will have problems.) Once you do that, a query like the following should give you what you're looking for, I believe. (Oh, and you have this question tagged as both SQL Server and MySQL. So I created this script on SQL Server 2008 r2.)
SET NOCOUNT ON;
DECLARE #Transmission TABLE (
ID int,
GroupID int,
Amount int,
TransmissionDate SmallDateTime );
INSERT #Transmission VALUES (1, 1, 5,'2015/05/20');
INSERT #Transmission VALUES (2, 1, 4,'2015/05/19');
INSERT #Transmission VALUES (3, 1,10,'2015/04/20');
INSERT #Transmission VALUES (4, 1, 7,'2015/04/19');
INSERT #Transmission VALUES (5, 1, 9,'2015/03/20');
INSERT #Transmission VALUES (6, 1, 2,'2015/03/18');
DECLARE #TableGroupRange TABLE (
ID int,
GroupID int,
BillStart SmallDateTime,
BillStop SmallDateTime );
INSERT #TableGroupRange VALUES (1, 1, '2015/03/15', '2015/04/14' )
INSERT #TableGroupRange VALUES (2, 1, '2015/04/15', '2015/05/14' )
INSERT #TableGroupRange VALUES (3, 1, '2015/05/15', '2015/06/14' )
SET NOCOUNT OFF;
SELECT TG.GroupID, SUM(T.Amount) as SumAmount, TG.BillStart, TG.BillStop
FROM #TableGroupRange TG
LEFT JOIN #Transmission T ON T.GroupID = TG.GroupID AND T.TransmissionDate BETWEEN TG.BillStart AND TG.BillStop
GROUP BY TG.GroupID, TG.BillStart, TG.BillStop
ORDER BY TG.GroupID, TG.BillStart, TG.BillStop

MySQL: Use data from one table to fill a second table using phpMyAdmin

SQL conundrum here.
I want to populate an empty table based on the data in an existing table using phpMyAdmin.
More specifically, I want to use the data in mark to create the data in attempt. The columns in mark are student_number, test_number, attempt_number, question_number and the answer. It's a multiple-choice test analysis tool.
mark (existing)
snum tnum anum qnum answer
----------------------------------------
1 1 1 1 A
1 1 1 2 C
1 1 1 3 D
1 1 2 1 B
1 1 2 2 A
1 1 2 3 C
attempt (to be created)
snum tnum anum period
--------------------------------
1 1 1 2013-1
1 1 2 2013-2
I can get the distinct snum, tnum, anum combinations as follows:
SELECT DISTINCT snum, tnum, anum FROM `mark`
How can I use the results from this call to populate the requisite insert call?
INSERT INTO `attempt` (snum,tnum,anum,period) VALUES (:s,:t,:a,"2013-1")
Ideally, I'd like to auto-complete the period value based on "2013-" plus the anum. I suspect this is not possible, so I'll just select all the anum=1 values, and hardcode the period value (and then repeat for each anum).
Thanks.
Use the "INSERT INTO SELECT" syntax:
INSERT INTO 'attempt'(snum,tnum,anum,period) SELECT DISTINCT snum,tnum,anum,CONCAT('2013-',anum) as period FROM mark;
INSERT INTO `attempt`
(snum,
tnum,
anum,
period)
select DISTINCT
snum,
tnum,
anum,
concat('2013-',anum) as period
from mark;

mysql query using condition inside sum

I have a column (*Purchasetype*), userid in video table purchasetype is some how containg values 0,1, 2,3,4,.. etc. I want two sum these value order by userid.
For ex: sum ( purchasetype ) order by userid but I want like this
if purchasetype= 0 then its value is 0.99
if purchasetype =1 or 20 then its value is 3.99
if purchasetype = 3 or 13or 22 then its value is 9.99
so on. Below is complete list
0 ,17= 0.99
1,20=3.99
2=6.99
3,13,22=9.99
4,5,6,7,8,,10,11,12=0.00
14=19.99
15,23=39.99
16,24=59.99
18,21=01.99
19=02.99
else
19.99
i want to sum all the values of purchasetype with their replaced values (given above) order by userid
do we can put condition inside the sum() function of mysql; If its possible then please give me solution , may be this will solve my problem
You would use the aggregate function SUM() and CASE:
select
SUM(CASE purchaseType
WHEN 0 or 17 THEN 0.99
WHEN 1 or 20 THEN 3.99
WHEN 3 or 13 or 22 THEN 9.99
WHEN 4 or 5 or 6 or 7 or 8 or 9 or 10 or 11 or 12 THEN 0
WHEN 14 THEN 19.99
WHEN 15 or 23 THEN 39.99
WHEN 16 or 24 THEN 59.99
WHEN 18 or 21 THEN 1.99
WHEN 19 THEN 2.99
ELSE 19.99 END) as Total
from yourTable
see SQL Fiddle with Demo
I think the best way is to create table ptPrices:
create table ptPrices (Purchasetype int, Price float);
insert into ptPrices values (0,0.99);
insert into ptPrices values (1,3.99);
....
insert into ptPrices values (19,2.99);
And then use this query:
select sum(isnull(ptPrices.Price,19.99)) from Table
left join ptPrices
on Table.Purchasetype=ptPrices.Purchasetype;
Although this doesn't use SUM from MySQL query, the logic will get the job done
$query = mysqli_query($link, "SELECT * FROM video");
while($row = mysqli_fetch_assoc($query)){
//Then set conditionals
if($row['purchase_type)==0 || $row['purchase_type)==17){
$values[] = 0.99;
//Then your mysqli_query here
}
elseif($row['purchase_type)==1 || $row['purchase_type)==20){
$values[]= 3.99;
}
elseif//Blah blah for all values
}
//After exhausting all the rows, add the SUM
$sum = array_sum($values); //$sum will be equal to the addition of all the vlues of the //array $values