MySQL with Mathematical calculations - mysql

I've created the database for library management system.
The Query is to be return for the question below !!!
Find fine payable(fine) against each student of particular department for past 6 months
Assumption: Fine amount is 2/day(either in cent or INR) and it'll double for the second day, likewise 2,4,8,16,32,64,128,256.......
my code for the question is:
SELECT
GROUP_CONCAT(s.id) AS IDs,
GROUP_CONCAT(DATEDIFF(returned,exp_date)) AS DAYS,
GROUP_CONCAT(POW(2,DATEDIFF(returned,exp_date))) AS FINE_PER_HEAD,
SUM(POW(2,DATEDIFF(returned,exp_date))) AS Fine,s.dept
FROM student s
INNER JOIN borrower b
ON s.id=b.id
WHERE returned>exp_date AND exp_date
BETWEEN DATE_SUB(NOW(), INTERVAL 6 MONTH) AND NOW()
GROUP BY s.dept;`
In the output i got 2^33 cent (33 days)in the fine Column Here,The Image contains the output screen of the result that i got from the query
IDs DAYS FINE_PER_HEAD Fine dept
----------------------------------------------------------------------------
1,36,138 2,5 4,32 36 CS
116,104,109,112 1,11,8,33 2,2048,256,8589934592 8589936898 Electronics
196 13 8192 8192 Maths
1,73,174 10,14 1024,16384 17408 Mechanical
1,48,150 6,5 64,32 96 Physics
How can i limit the fine amount that should not exceed the particular amount like < 5000 or 6000 cent> whatever , what should i do?

Related

Combining between two tables in MySQL and getting the distinct answer

I know this has probably been asked before but I am trying to find the correct way to this and I have been struggling for the past week or so.
So we have two sets of data for example, one table is called 'Order Log' and another is called 'Customer Information'
and here are example of the two data set
NOTE: The order log will sometimes have order from the same customer twice
Order Log Table
Customer ID
Date
Order Number
Order Amount
sgcwi
2022-06-11
124
3
gbtfc
2022-07-09
12
4
crownwood
2022-04-08
123
1
kcsi
2022-02-24
543
1
ulsteri
2022-08-08
423
2
gbtfc
2022-07-08
1254
3
ulsteri
2022-04-08
345
2
kcsi
2022-07-13
64
1
crownwood
2022-07-04
55
1
Customer Information Table
Customer Name
Customer ID
Contact
Sagen Private
sgcwi
email
Granten Viel
gbtfc
phone
Crownwood LTD
crownwood
email
Kings College
kcsi
email
Ulster FC
ulsteri
phone
So what my question is, how do i write an sql query that gives me back the the last order for each customer from the Order Log table withhin a span of the last 6 Months and returns me back the customer name for each of those selected data from the customer Informationt table. like such
The Sql Query Return that i want
Customer Name
Customer ID
Date
Sagen Private
sgcwi
2022-06-11
Granten Viel
gbtfc
2022-06-11
Crownwood LTD
crownwood
2022-07-04
Kings College
kcsi
2022-07-13
Ulster FC
ulsteri
2022-08-08
so far I have figured out to get the result from the Log table that I gave to use the query
"SELECT DISTINCT orderLog.customerID FROM Order WHERE qslogv2.date >= DATE_ADD(NOW(), INTERVAL -3 MONTH);
But I am yet to figure out how do i connect the Customer Information table to this query so it returns me the appropriate customer name along with the query.
I tried using the above query that I mentioned and also tried the UNION keyword in MySQL but to my demise I was not able to get to a point where I got that desired result.
Use JOIN-statement combined with MAX + GROUP BY.
In JOIN you tell what columns match in the joined tables. In your case it is the Customer ID.
With GROUP BY, you divide the rows into sets (based on the customer) and then applies the MAX-function for each of those sets, so that you will get the latest date for each customer.
select
c.name,
c.id,
max(ol.date)
from customerInformation c
join orderLog ol on ol.customerID=c.id
where ol.date between date_sub(now(), interval 6 month) and now()
group by c.name, c.id

SQL to retrieve name of user making transactions under certain time

I am trying to create features for my ML work on a grocery customers data.
The data has transaction which user makes in buying groceries.
I am trying to find the name of the users who have made consecutive transactions within 30 seconds time frame. This is important to get a profile of such users
So for example if data looks like below:
User Datetime Amount
1 Mary 2020-11-30 10:10:20 24
2 Jacob 2020-11-30 12:12:12 43.2
3 Alice 2020-11-30 11:11:11 75.29
4 Mary 2020-11-30 10:10:45 34
5 Mary 2020-11-30 10:11:15 21
6 Alice 2020-11-30 11:11:41 100
the correct answer would be Alice as only Alice had more than 1 transactions which are within 30 seconds time frame.
Mary might appear as probable answer but not all consecutive transactions had 30 seconds gap. It had 25 and 30. So correct answer we need is Alice
One method is lag() to get the time of the previous transaction. The following returns the transactions that are within 30 seconds:
select t.*
from (select t.*,
lag(datetime) over (partition by user order by datetime) as prev_datetime
from t
) t
where prev_datetime > datetime - interval '30 second';
This syntax uses standard SQL; date/time functions vary among databases, so the exact syntax depends on the database you are using.
It is unclear how you want to summarize this to get Alice but not Mary.
If you need for all transactions to be exactly 30 seconds, you can use:
select user
from (select t.*,
lag(datetime) over (partition by user order by datetime) as prev_datetime
from t
) t
group by user
having sum(prev_datetime <> datetime - interval 30 second) = 0;

How do I select row with the most recent reduction in a column value from same columns value in previous row?

I have a set of inventory data where the amount increases at a given rate. For example, the inventory increases by ten units every day. However, from time to time there will be an inventory reduction that could be any amount. I need a query that can find me the most recent inventory reduction and return to me the sum of that deduction.
My table holds date and amount for numerous item id's. In theory what I am trying to do is select all amounts and dates for a given item ID, and then find the difference between the most recent reduction between two days inventory. Due to the fact that multiple items are tracked, there is no guarantee that the id column will be consecutive for a set of items.
Researching to find a solution to this has been completely overwhelming. It seems like window functions might be a good route to try, but I have never used them and don't even really have a concept of where to start.
While I could easily return the amounts and do the calculation in PHP, I feel the right thing to do here is harness SQL but my experience with more complex queries is limited.
ID | ItemID | Date | Amount
1 2 2019-05-05 25
7 2 2019-05-06 26
34 2 2019-05-07 14
35 2 2019-05-08 15
67 2 2019-05-09 16
89 2 2019-05-10 5
105 2 2019-05-11 6
Given the data above, it would be nice to see a result like:
item id | date | reduction
2 2019-05-10 11
This is because the most recent inventory reduction is between id 67 and 89 and the amount of the reduction is 11 on May 10th 2019.
In MySQL 8+, you can use lag():
select t.*, (prev_amount - amount) as reduction
from (select t.*,
lag(amount) over (partition by itemid order by date) as prev_amount
from t
) t
where prev_amount > amount
order by date desc
limit 1;

SQL Query - Pull data from ambiguous column names for growth/decline %

Re-post due to bad data set and bad formatting. I am trying to divide data from two separate tables that have ambiguous column names.
I am newer to SQL, I know it should be simple, however I just can not figure it out. So far I have tried to rename columns, alias columns, union the table, and select multiple data sets.
I keep hitting roadblocks.
I am trying to measure growth or decline week over week. Ideally I want to take the total sales for Plates and do the following equation: (75/100-1) which would equal a -25% decline from last week.
What would be the best way to go about this?
The two example tables are below
LastWeekData
Product Day Month TotalSales
Plates 7 3 $100
Spoons 7 3 $150
Forks 7 3 $120
CurrentData
Product Day Month TotalSales
Plates 14 3 $75
Spoons 14 3 $100
Forks 14 3 $115
You can use table alias to differentiate the table columns that you want to display. See demo here: http://sqlfiddle.com/#!9/0b0d81/29
select cur.Product,
cur.Day,
cur.Month,
cur.TotalSales as currweek_TotalSales,
pre.TotalSales as lastweek_TotalSales,
round((cur.TotalSales/pre.TotalSales-1)*100) as percent_change
from CurrentData as cur
inner join LastWeekData as pre
on pre.product=cur.product
where datediff(str_to_date(concat_ws('-','0001',cur.month,cur.day),'%Y-%m-%d'),
str_to_date(concat_ws('-','0001',pre.month,pre.day),'%Y-%m-%d'))
= 7
Result:
Product Day Month currweek_TotalSales lastweek_TotalSales percent_change
Plates 14 3 75 100 -25
Spoons 14 3 100 150 -33
Forks 14 3 115 120 -4

Getting count of rows with multiple combinations

I need help with a MySQL query. We have a database (~10K rows) which I have simplified down to this problem.
We have 7 truck drivers who visit 3 out of a possible 9 locations, daily. Each day they visit exactly 3 different locations and each day they can visit different locations than the previous day. Here are representative tables:
Table: Drivers
id name
10 Abe
11 Bob
12 Cal
13 Deb
14 Eve
15 Fab
16 Guy
Table: Locations
id day address driver.id
1 1 Oak 10
2 1 Elm 10
3 1 4th 10
4 1 Oak 16
5 1 4th 16
6 1 Toy 16
7 1 Toy 11
8 1 5th 11
9 1 Law 11
10 2 Oak 11
11 2 4th 11
12 2 Toy 11
.........
We have data for a full year and we need to find out how many times each "route" is visited over a year, sorted from most to least.
From my high school math, I believe there are 9!/(6!3!) route combinations, or 84 in total. I want do something like:
Get count of routes where route addresses = 'Oak' and 'Elm' and '4th'
then run again
where route addresses = 'Oak' and 'Elm' and '5th'
then again and again, etc.Then sort the route counts, descending. But I don't want to do it 84 times. Is there a way to do this?
I'd be looking at GROUP_CONCAT
SELECT t.day
, t.driver
, GROUP_CONCAT(t.address ORDER BY t.address)
FROM mytable t
GROUP
BY t.day
, t.driver
What's not clear here, if there's an order to the stops on the route. Does the sequence make a difference, and how to we tell what the sequence is? To ask that a different way, consider these two routes:
('Oak','Elm','4th') and ('Elm','4th','Oak')
Are these equivalent (because it's the same set of stops) or are they different (because they are in a different sequence)?
If sequence of stops on the route distinguishes it from other routes with the same stops (in a different order), then replace the ORDER BY t.address with ORDER BY t.id or whatever expression gives the sequence of the stops.
Some caveats with GROUP_CONCAT: the maximum length is limited by the setting of group_concat_max_len and max_allowed_packet variables. Also, the comma used as the separator... if we combine strings that contain commas, then in our result, we can't reliably distinguish between 'a,b'+'c' and 'a'+'b,c'
We can use that query as an inline view, and get a count of the the number of rows with identical routes:
SELECT c.route
, COUNT(*) AS cnt
FROM ( SELECT t.day
, t.driver
, GROUP_CONCAT(t.address ORDER BY t.address) AS route
FROM mytable t
GROUP
BY t.day
, t.driver
) c
GROUP
BY c.route
ORDER
BY cnt DESC