Table Historical_Inventory
Column: Date, Prod_ID, WHStock, Stock_Allocated
I want to count the amount of times a products (WHstock - stock allocated) <= 0 between date x and y where Prod_ID = "id1"
Any ideas?
I was going along the lines of
SELECT Count `Prod_ID`
, sum((`WHStock`-`Stock_Allocated`)) as Stock
from Historic_Inventory
WHERE `Date` Between '2018-04-01'and '2018-08-01'
AND Stock <= 0
But not working very well..
I think you want:
SELECT COUNT(*)
FROM (SELECT Prod_ID, SUM(WHStock - Stock_Allocated) as Stock
FROM Historic_Inventory
WHERE `Date` Between '2018-04-01' and '2018-08-01'
GROUP BY Prod_ID
) x
WHERE Stock <= 0;
Hmmm. . . this counts the number of products where the value is negative.
Perhaps you want:
select hi.*
(#stock := #stock + (WHStock - Stock_Allocated)) as stock
from (select hi.*
from historic_inventory hi
where prod_id = ?
order by date
) hi cross join
(select #stock := 0) params
having stock < 0;
Try this:
SELECT Count(*)
FROM
(SELECT SUM((`WHStock`-`Stock_Allocated`)) AS Stock
FROM Historic_Inventory
WHERE `Date` Between '2018-04-01'and '2018-08-01') AS t
WHERE t.Stock <= 0
Related
I have following query:
SELECT x.id , x.amount , x.amount as paid_amount , SUM(y.bal) as total, x.reciept_no
FROM (SELECT *, paid bal
FROM challan_1 ) x
JOIN (SELECT *, amount bal
FROM challan_1 ) y
ON y.id <= x.id
GROUP BY x.id
HAVING total <= '500'
it's working quite fine. And output like
And then I made a new query that is as below
SELECT *, (CASE WHEN 500-sum(amount) >= 0
THEN '0'
ELSE 500-SUM(paid) END) as pending_amt
FROM challan_1
Output is
This query returns me a Pending Amount so I need to combine both queries so how can I combine both queries.
I need this pending amount in first query.
This is My SQL Fiddle
And I need Like This. Where User Have 500 Currency And Have 3 Payment So for that situation Output Should be like this.
Where 100 Is in pending amount and 200 from user value is debited.
I don't completely understand, but here is my take on this. 500 available. There are records where payments are made. Strange enough even beyond 500, so I assume these are would-be expenses/payments if there were more money available. I stop where payments exceed the 500.
SELECT
challan.*,
SUM(addup.amount) as total_amount,
sum(addup.paid) as total_paid,
sum(addup.amount) - sum(addup.paid) as total_pending,
sum(addup.amount) <= sum(addup.paid) as status
FROM challan_1 challan
JOIN challan_1 addup ON addup.id <= challan.id
GROUP BY challan.id
HAVING sum(addup.paid) <= 500
ORDER BY challan.id;
If you want to show further records, i.e. get rid of the HAVING clause, you'll need another formula for the pending amount, for the highest paid amount possible is 500:
SELECT
challan.*,
SUM(addup.amount) as total_amount,
sum(addup.paid) as total_paid,
sum(addup.amount) - least(500, sum(addup.paid)) as total_pending,
sum(addup.amount) <= least(500, sum(addup.paid)) as status
FROM challan_1 challan
JOIN challan_1 addup ON addup.id <= challan.id
GROUP BY challan.id
ORDER BY challan.id;
Add the subquery as another join.
SELECT x.id , x.amount , x.amount as paid_amount , SUM(y.bal) as total, x.reciept_no, p.pending_amt
FROM (SELECT *, paid bal
FROM challan_1 ) x
JOIN (SELECT *, amount bal
FROM challan_1 ) y
ON y.id <= x.id
CROSS JOIN (SELECT CASE WHEN SUM(amount) <= 500
THEN '0'
ELSE 500 - SUM(paid)
END AS pending_amt
FROM challan_1) AS p
GROUP BY x.id
HAVING total <= '500'
Let us suppose we have following tables
product_id | quantity
1 | 250
2 | 150
3 | 120
4 | 300
5 | 301
How do we know that the item number of 401th in SQL? (the answer should be product_id : 3). The query should return the product_id
Let us assume also the row has been in order
You can use Correlated query to find cummulative sum and then filter range using between to find the required slot:
select product_id
from (
select a.*,
coalesce((
select sum(quantity)
from your_table b
where b.product_id < a.product_id
), 0) + 1 cquant1,
(
select sum(quantity)
from your_table b
where b.product_id <= a.product_id
) cquant2
from your_table a
) t
where 401 between cquant1 and cquant2;
Demo
You can also use user variable for this:
select *
from (
select product_id,
#sum1 := #sum1 + coalesce((
select quantity
from your_table x
where x.product_id < t.product_id
order by x.product_id desc limit 1
), 0) as cquantity1,
#sum2 := #sum2 + quantity as cquantity2
from your_table t,
(select #sum1 := 0, #sum2 := 0) t2
order by product_id
) t
where 401 between cquantity1 and cquantity2;
Demo
In case of ORACLE, this will not work with SQLServer
This is by using LAG and SUM OVER() functions,
SELECT PRODUCT_ID FROM
(
SELECT PRODUCT_ID
, LAG(CUM_QUAN, 1, 0) OVER (ORDER BY PRODUCT_ID) AS START_QUAN
, CUM_QUAN END_QUAN
FROM
(
SELECT PRODUCT_ID
, QUANTITY
, SUM(QUANTITY) OVER (ORDER BY PRODUCT_ID) AS CUM_QUAN
FROM YOUR_TABLE
)
) WHERE 401 BETWEEN START_QUAN AND END_QUAN
You can do this with variables by getting a cumulative sum. However, Gurv's answer is way too complicated.
I think this is the simplest way:
select t.*
from (select t.*, (#s := #s + quantity) as running_quantity
from t cross join
(select #s := 0) params
order by product_id
) t
where 401 < running_quantity and
401 >= running_quantity - quantity;
I have a mysql table, transactions, with fields id, transactionType, quantity, price etc. I want to limit records by the cumulative sum of one column. So I want to pull out all the transactions until the cumulative quantity reaches my variable (here <=50).
What am I doing wrong?
SET #qsum := 0;
SELECT *
FROM (
SELECT *, (#qsum := #qsum + quantity) AS cumulative_quantity
FROM transactions ORDER BY id DESC
) transactions
WHERE
transactionType = 'buy'
AND typeID = 10
AND cumulative_quantity <= 50
Try this way
SET #qsum := 0;
SELECT *
FROM (
SELECT *, (#qsum := #qsum + quantity) AS cumulative_quantity
FROM transactions
WHERE transactionType = 'buy'
AND typeID = 10
AND cumulative_quantity <= 50
ORDER BY id DESC
) transaction
What im trying to achieve is to get the current count and last month count so i can do a formula to get the growth percentage
(CountCurrent - CountLastMonth) / CountLastMonth
My table has the following fields
activity, upload_date
This is the query im trying now.
SELECT
Y.CurrentMonth, Y.CountCurrent,
Z.LastMonth, Z.CountLastMonth
FROM
(SELECT
upload_date,
activity,
DATE_FORMAT(upload_date,'%M %Y') AS CurrentMonth,
COUNT(activity) AS CountCurrent
FROM appmaster
WHERE activity = 'com.google.test'
GROUP BY DATE_FORMAT(upload_date,'%m%y'))
Y INNER JOIN
(SELECT
activity,
DATE_FORMAT(upload_date,'%M %Y') AS CurrentMonth2,
DATE_FORMAT(upload_date - INTERVAL 1 MONTH,'%M %Y') AS LastMonth,
COUNT(activity) AS CountLastMonth
FROM appmaster
WHERE activity = 'com.google.test'
GROUP BY DATE_FORMAT(upload_date - INTERVAL 1 MONTH,'%m%y'))
Z ON Z.CurrentMonth2 = Y.CurrentMonth
GROUP BY DATE_FORMAT(upload_date,'%Y%m')
ORDER BY DATE_FORMAT(upload_date,'%Y%m')
My CurrentMonth, CountCurrent and LastMonth work fine. But the CountLastMonth is coming out the same as CountCurrent.
I was trying this before and it would give me everything but the CountLastMonth
SELECT b.CurrentMonth, sum(b.CountCurrent), b.LastMonth
FROM (SELECT DATE(a.upload_date - INTERVAL 1 MONTH) AS LastMonth, DATE(a.upload_date) AS CurrentMonth, COUNT(a.activity) AS CountCurrent
FROM appmaster a WHERE a.activity = 'com.google.android.googlequicksearchbox'
group BY MONTH(a.upload_date)) AS b
group BY MONTH(b.CurrentMonth)
No temporary table required:
SELECT
a.ym,
CASE #totals
WHEN 0 THEN 0
ELSE (a.totals - #totals) / #totals
END increment,
#totals := a.totals totals
FROM
(
SELECT
EXTRACT(YEAR_MONTH FROM upload_date) ym,
COUNT(1) AS totals
FROM
appmaster
WHERE
activity = 'com.google.test'
GROUP BY ym -- no ORDER BY required
) a
CROSS JOIN (SELECT #totals := 0) x
Maybe there's a simpler way to do this, using a little trick with user variables.
First, you need to write a query that groups your data by month; I'll store it in a temp table to ease things a bit:
drop table if exists temp_count;
create temporary table temp_count
select last_day(upload_date) as month -- A little trick to get
-- the last day of the month
, count(activity) as count_current
-- Add any other fields or expressions you need
from app_master
-- Add the needed joins
-- Include any WHERE conditions here
group by last_day(upload_date);
-- Let's add an index to this temp table... add any indexes you may need
alter table temp_count
add index idx_month(month);
And now, let's use this temp table to get what you need:
select a.month
, #count_last as count_last -- This is the value of the user variable
-- before reassigning it
, (a.count_current - #count_last) / #count_last as increment
, #count_last := a.count_current -- Here the variable is updated with the
-- current value
from
( -- This subquery is used to initialize the user variable
select #count_last := 0
) as init
, temp_count as a
-- It's important to order the data, otherwise God knows what may happen ;)
order by a.month;
Hope this helps
#Rental number Growth per month -- This is the example for monthly growth where "Total count of activity per month" is concerned -- This answer was developed based on Barranka answer and credit goes to him.
SELECT
a.YM,
CASE #Num_of_Rentals
WHEN 0 THEN 0
ELSE (a.Num_of_Rentals - #Num_of_Rentals) / #Num_of_Rentals
END increment,
#Num_of_Rentals := a.Num_of_Rentals Num_of_Rentals
FROM
(
SELECT
LEFT(rental_date,7) YM,
COUNT(rental_id) AS Num_of_Rentals
FROM
rental
GROUP BY ym -- no ORDER BY required
) a
CROSS JOIN (SELECT #Num_of_Rentals := 0) x;
-- OR
SELECT
a.YM,
CASE #Num_of_Rentals
WHEN 0 THEN 0
ELSE (a.Num_of_Rentals - #Num_of_Rentals) / #Num_of_Rentals
END increment,
#Num_of_Rentals := a.Num_of_Rentals Num_of_Rentals
FROM
(
SELECT
LEFT(rental_date,7) YM,
COUNT(1) AS Num_of_Rentals
FROM
rental
GROUP BY ym -- no ORDER BY required
) a
CROSS JOIN (SELECT #Num_of_Rentals := 0) x;
Revenue growth over each month - This is based on the answer provided by Barranka but it is suitable for Monthly revenue growth:
SELECT
a.YM,
CASE #Revenue
WHEN 0 THEN 0
ELSE (a.Revenue - #Revenue) / #Revenue
END Increment,
#Revenue := a.Revenue Revenue
FROM
(
SELECT
LEFT(payment_date, 7) YM,
SUM(amount) AS Revenue -- Toatl is SUM of Amount
FROM
payment
GROUP BY YM -- no ORDER BY required
) a
CROSS JOIN (SELECT #Revenue := 0) x
;
SELECT
a.YM,
CASE #Revenue
WHEN 0 THEN 0
ELSE (a.Revenue - #Revenue) / #Revenue
END Increment,
#Revenue := a.Revenue Revenue
FROM
(
SELECT
EXTRACT(YEAR_MONTH FROM payment_date) YM,
SUM(amount) AS Revenue
FROM
payment
GROUP BY YM -- no ORDER BY required
) a
CROSS JOIN (SELECT #Revenue := 0) x
;
I have a table orders like this:
customer_id order_date
10 2012-01-01
11 2012-01-02
10 2012-01-02
12 2012-01-03
11 2012-01-04
12 2012-02-01
11 2012-02-04
13 2012-02-05
14 2012-02-06
How can I get a cumulative average over time (per month) like this:
order date count orders count customers (customer_id)
2012-01 1 1 (12)
2012-01 2 2 (10,11)
2012-02 1 2 (13,14)
2012-02 2 2 (10,12
2012-02 3 2 (11)
showing how the number of customers vs. number of orders per customer develops over time.
The following query gives me the wanted information - but not over time. How can I iterate the query over time?
SELECT number_of_orders, count(*) as amount FROM (
SELECT o.customer_id, count(*) as number_of_orders
FROM orders o
GROUP BY o.customer_id) as t1
GROUP BY number_of_orders
Update:
have now build the following PHP code to generate what I need, wonder if that could be done using cumulative counts like on http://www.freeopenbook.com/mysqlcookbook/mysqlckbk-chp-12-sect-14.html
$year = 2011;
for ($cnt_months = 1; $cnt_months <= 12; $cnt_months++) {
$cnt_months_str = ($cnt_months < 10) ? '0'.$cnt_months : $cnt_months;
$raw_query = "SELECT number_of_orders, count(*) as amount
FROM (
SELECT
o.customer_id,
count(*) as number_of_orders
FROM orders o
where Date_Format( o.order_date, '%Y%m' ) >= " . $year . "01 and Date_Format( o.order_date, '%Y%m' ) <= " . $year . $cnt_months_str . "
GROUP BY o.customer_id) as t1
GROUP BY number_of_orders";
$query = db_query($raw_query);
while ($row = db_fetch_array($query)) {
$data[$cnt_months_str][$row['number_of_orders']] = array($row['number_of_orders'], (int)$row['amount']);
}
}
A good starting point is
SELECT
order_date,
COUNT(*) AS distinctOrders,
COUNT(DISTINCT customer_id) AS distinctCustomers,
GROUP_CONCAT(DISTINCT customer_id ASC) AS customerIDs
FROM orders
GROUP BY order_date ASC
This will give you the order_date, the number of orders on that date, the number of customers on that date, and the list of customer ids on that date.
Just looking at a way to tally up on a month by month basis. So taking this forward I've used a subquery to tally up as it goes
SELECT
ordersPerDate.*,
IF(
MONTH(ordersPerDate.order_date)=#thisMonth,
#runningTotal := #runningTotal+ordersPerDate.distinctOrders,
#runningTotal := 0
) AS ordersInThisMonth,
#thisMonth := MONTH(ordersPerDate.order_date)
FROM
(
SELECT
#thisMonth := 0,
#runningTotal := 0
) AS variableInit,
(
SELECT
order_date,
COUNT(*) AS distinctOrders,
COUNT(DISTINCT customer_id) AS distinctCustomers,
GROUP_CONCAT(DISTINCT customer_id ASC) AS customerIDs
FROM orders
GROUP BY order_date ASC
) AS ordersPerDate
And finally to clean it up, wrapped it in yet another subquery just to return the rows desired rather than the internal variables
Grouping on individual days
SELECT
collatedData.order_date,
collatedData.ordersInThisMonth AS count_orders,
collatedData.distinctCustomers AS count_customers,
collatedData.customerIDs AS customer_ids
FROM (
SELECT
ordersPerDate.*,
IF(
MONTH(ordersPerDate.order_date)=#thisMonth,
#runningTotal := #runningTotal+ordersPerDate.distinctOrders,
#runningTotal := 0
) AS ordersInThisMonth,
#thisMonth := MONTH(ordersPerDate.order_date)
FROM
(
SELECT
#thisMonth := 0,
#runningTotal := 0
) AS variableInit,
(
SELECT
order_date,
COUNT(*) AS distinctOrders,
COUNT(DISTINCT customer_id) AS distinctCustomers,
GROUP_CONCAT(DISTINCT customer_id) AS customerIDs
FROM orders
GROUP BY order_date ASC
) AS ordersPerDate
) AS collatedData
And now finally, following additional information from the OP, the end product
Grouping on calendar months
// Top level will sanitise the output
SELECT
collatedData.orderYear,
collatedData.orderMonth,
collatedData.distinctOrders,
collatedData.ordersInThisMonth AS count_orders,
collatedData.distinctCustomers AS count_customers,
collatedData.customerIDs AS customer_ids
FROM (
// This level up will iterate through calculating running totals
SELECT
ordersPerDate.*,
IF(
(ordersPerDate.orderYear,ordersPerDate.orderMonth) = (#thisYear,#thisMonth),
#runningTotal := #runningTotal+ordersPerDate.distinctOrders*ordersPerDate.distinctCustomers,
#runningTotal := 0
) AS ordersInThisMonth,
#thisMonth := ordersPerDate.orderMonth,
#thisYear := ordersPerDate.orderYear
FROM
(
SELECT
#thisMonth := 0,
#thisYear := 0,
#runningTotal := 0
) AS variableInit,
(
// Next level up will collate this to get per year, month, and per number of orders
SELECT
ordersPerDatePerUser.orderYear,
ordersPerDatePerUser.orderMonth,
ordersPerDatePerUser.distinctOrders,
COUNT(DISTINCT ordersPerDatePerUser.customer_id) AS distinctCustomers,
GROUP_CONCAT(ordersPerDatePerUser.customer_id) AS customerIDs
FROM (
// Inner query will get the number of orders for each year, month, and customer
SELECT
YEAR(order_date) AS orderYear,
MONTH(order_date) AS orderMonth,
customer_id,
COUNT(*) AS distinctOrders
FROM orders
GROUP BY orderYear ASC, orderMonth ASC, customer_id ASC
) AS ordersPerDatePerUser
GROUP BY
ordersPerDatePerUser.orderYear ASC,
ordersPerDatePerUser.orderMonth ASC,
ordersPerDatePerUser.distinctOrders DESC
) AS ordersPerDate
) AS collatedData
SELECT
substr(order_date,1,7) AS order_period,
count(*) AS number_of_orders,
count(DISTINCT orders.customer_id) AS number_of_customers,
GROUP_CONCAT(DISTINCT orders.customer_id) AS customers
FROM orders
GROUP BY substr(order_date,1,7)