I have a table like Bikes
name mfgdate qtysold
bajaj 1/1/2016 12:00:00 AM 48
bajaj 1/1/2017 12:00:00 AM 49
bajaj 1/1/2018 12:00:00 AM 50
pulsar 1/1/2016 12:00:00 AM 300
pulsar 1/1/2017 12:00:00 AM 250
pulsar 1/1/2018 12:00:00 AM 200
yamaha 1/1/2016 12:00:00 AM 90
yamaha 1/1/2017 12:00:00 AM 180
yamaha 1/1/2018 12:00:00 AM 100
From the above table i need a select Query to get the output of the increased sales
like
eg: output
name
Bajaj
because Bajaj has the increased sales. Yamaha also have a increased sales but it decreased in 2018..
Thanks in advance..
Based on OP's comments, it is required to find only those Bike names, which has never seen decrease in sales.
Following solution will work on All MySQL Versions (especially < 8.0)
Using a Correlated subquery, we find previous qtysold value for a bike. If not found, using Ifnull() function, consider it as zero
Calculate change (qtysold - previous qtysold)
Now, using this as Derived table, we can get all those Distinct bike name(s), where change has always been > 0
You can try the following (check SQL Fiddle):
SELECT t3.name
FROM
(
SELECT t1.name,
(t1.qtysold - IFNULL(
(SELECT t2.qtysold
FROM Bikes as t2
WHERE t2.name = t1.name
AND t2.mfgdate < t1.mfgdate
ORDER BY t2.mfgdate DESC LIMIT 1)
, 0
)) AS sales_change
FROM Bikes as t1
) AS t3
GROUP BY t3.name
HAVING MIN(t3.sales_change) > 0
You can use a SELF JOIN to get desired result. Inner query will return the names of all Bikes which have a dip in sales. You can use NOT IN clause then to find the left-out result entries.
SELECT DISTINCT b.name
FROM Bikes b
WHERE
b.name NOT IN (
SELECT DISTINCT b1.name
FROM
Bikes b1
INNER JOIN
Bikes b2
ON b1.name = b2.name
AND b1.mfgdate < b2.mfgdate
AND b1.qtysold > b2.qtysold
);
You can use window function :
select t.*,
sum(case when exists (select 1
from table t1
where t1.name = t.name and t1.mfgdate > t.mfgdate and t1.qtysold < t.qtysold
)
then 1 else 0 end
) over (partition by name) as grp
from table t;
Now you can filter out the names which has increaed sales :
select t.*
from ( <subquery here> ) t
where t.grp = 0;
MySQL Self Join:
SELECT
*
FROM
Bikes AS this_year
LEFT JOIN
Bikes AS prev_year
ON prev_year.name = this_year.name
AND prev_year.mfgdate = DATE_SUB(this_year.mfgdate, INTERVAL 1 YEAR)
GROUP BY
this_year.name
HAVING
MIN(this_year.qtysold - COALESCE(prev_year.qtysold, 0)) > 0
MariaDB LAG():
WITH
historicised AS
(
SELECT
*,
LAG(qtysold) OVER (PARTITION BY name
ORDER BY mfgdate
)
AS prev_qtysold
FROM
Bikes
)
SELECT
name
FROM
historicised
GROUP BY
name
HAVING
MIN(qtysold - COALESCE(prev_qtysold, 0)) > 0
Related
I have below table
AccountID
Date
Amount
123
07/06/2021
2000
123
07/12/2021
9000
123
07/16/2021
500
123
07/20/2021
500
123
07/28/2021
500
I am trying to sum the amount over 5 working days and get the output like below
AccountID
Date
Sum Amount
123
07/06/2021
11000
123
07/12/2021
9500
123
07/16/2021
1000
123
07/20/2021
500
123
07/28/2021
500
Also I am trying to ignore weekends(Saturday and Sunday)
I was able to add over 5 days using the below query. But not able to skip weekends.
Select distinct
t1.accountid,
convert(datetime,t1.[date]),
t1.amount,
sum(t2.amount)
from [dbo].[HANMI_ABRIGO_TRANSACTIONS] t1
cross apply
(
SELECT *
FROM [dbo].[HANMI_ABRIGO_TRANSACTIONS] a
WHERE a.accountid= t1.accountid
AND
(
convert(datetime,a.[date]) < DATEADD(DAY,5,convert(datetime,t1.[date]))
AND
convert(datetime,a.[date]) >= convert(datetime,t1.[date])
)
And a.accountid = '123'
And a.date like '2021-07%'
and a.amount > 0
)t2
where t1.accountid = '123'
And t1.date like '2021-07%'
and t1.amount > 0
group by
t1.accountid,
convert(datetime,t1.[date]),
t1.amount
order by convert(datetime,t1.[date])
Thanks!
I think this is the query you are asking for:
SELECT AccountId, Date,
(
SELECT SUM(Amount)
FROM HANMI_ABRIGO_TRANSACTIONS h2
WHERE
h1.AccountID = h2.AccountID and
DATEPART(WEEKDAY, h2.Date) not in (1, 7) and
h2.Date between h1.Date AND DATEADD(d, 5, h1.Date)
) as SumAmount
FROM HANMI_ABRIGO_TRANSACTIONS h1
The results are:
AccountId
Date
SumAmount
123
2021-07-06
2000
123
2021-07-12
9500
123
2021-07-16
1000
123
2021-07-20
500
123
2021-07-28
500
SQL Fiddle: http://sqlfiddle.com/#!18/3d6bae/8
I have a problem with writing a query.
Row data is as follow :
DATE CUSTOMER_ID AMOUNT
20170101 1 150
20170201 1 50
20170203 1 200
20170204 1 250
20170101 2 300
20170201 2 70
I want to know when(which date) the sum of amount for each customer_id becomes more than 350,
How can I write this query to have such a result ?
CUSTOMER_ID MAX_DATE
1 20170203
2 20170201
Thanks,
Simply use ANSI/ISO standard window functions to calculate the running sum:
select t.*
from (select t.*,
sum(t.amount) over (partition by t.customer_id order by t.date) as running_amount
from t
) t
where running_amount - amount < 350 and
running_amount >= 350;
If for some reason, your database doesn't support this functionality, you can use a correlated subquery:
select t.*
from (select t.*,
(select sum(t2.amount)
from t t2
where t2.customer_id = t.customer_id and
t2.date <= t.date
) as running_amount
from t
) t
where running_amount - amount < 350 and
running_amount >= 350;
ANSI SQL
Used for the test: TSQL and MS SQL Server 2012
select
"CUSTOMER_ID",
min("DATE")
FROM
(
select
"CUSTOMER_ID",
"DATE",
(
SELECT
sum(T02."AMOUNT") AMOUNT
FROM "TABLE01" T02
WHERE
T01."CUSTOMER_ID" = T02."CUSTOMER_ID"
AND T02."DATE" <= T01."DATE"
) "AMOUNT"
from "TABLE01" T01
) T03
where
T03."AMOUNT" > 350
group by
"CUSTOMER_ID"
GO
CUSTOMER_ID | (No column name)
----------: | :------------------
1 | 03/02/2017 00:00:00
2 | 01/02/2017 00:00:00
db<>fiddle here
DB-Fiddle
SELECT
tmp.`CUSTOMER_ID`,
MIN(tmp.`DATE`) as MAX_DATE
FROM
(
SELECT
`DATE`,
`CUSTOMER_ID`,
`AMOUNT`,
(
SELECT SUM(`AMOUNT`) FROM tbl t2 WHERE t2.`DATE` <= t1.`DATE` AND `CUSTOMER_ID` = t1.`CUSTOMER_ID`
) AS SUM_UP
FROM
`tbl` t1
ORDER BY
`DATE` ASC
) tmp
WHERE
tmp.`SUM_UP` > 350
GROUP BY
tmp.`CUSTOMER_ID`
Explaination:
First I select all rows and subselect all rows with SUM and ID where the current row DATE is smaller or same as all rows for the customer. From this tabe i select the MIN date, which has a current sum of >350
I think it is not an easy calculation and you have to calculate something. I know It could be seen a little mixed but i want to calculate step by step. As fist step if we can get success for your scenario, I believe it can be made better about performance. If anybody can make better my query please edit my post;
Unfortunately the solution that i cannot try on computer is below, I guess it will give you expected result;
-- Get the start date of customers
SELECT MIN(DATE) AS DATE
,CUSTOMER_ID
INTO #table
FROM TABLE t1
-- Calculate all possible date and where is sum of amount greater than 350
SELECT t1.CUSTOMER_ID
,SUM(SELECT Amount FROM TABLE t3 WHERE t3.DATE BETWEEN t1.DATE
AND t2.DATE) AS total
,t2.DATE AS DATE
INTO #tableCalculated
FROM #table t1
INNER JOIN TABLE t2 ON t.ID = t2.ID
AND t1.DATE != t2.DATE
WHERE total > 350
-- SELECT Min amount and date for per Customer_ID
SELECT CUSTOMER_ID, MIN(DATE) AS DATE
FROM #tableCalculated
GROUP BY ID
SELECT CUSTOMER_ID, MIN(DATE) AS GOALDATE
FROM ( SELECT cd1.*, (SELECT SUM(AMOUNT)
FROM CustData cd2
WHERE cd2.CUSTOMER_ID = cd1.CUSTOMER_ID
AND cd2.DATE <= cd1.DATE) AS RUNNINGTOTAL
FROM CustData cd1) AS custdata2
WHERE RUNNINGTOTAL >= 350
GROUP BY CUSTOMER_ID
DB Fiddle
I want to get all the records from two tables, calculating the sum of the amount grouped by day, but showing all the records from both, when the date match show both values.
For example I have:
table 1 In
id ammount date
1 300 2017-10-25
2 150 2017-10-25
3 550 2017-10-27
table 2 out
1 250 2017-10-27
2 410 2017-10-28
3 830 2017-10-29
and I want this result:
result
ammount in ammount out date
450 0 2017-10-25
550 250 2017-10-27
0 410 2017-10-28
0 830 2017-10-29
any idea how to make this?
This works with SQLite3:
create table t1(id,amount,date);
insert into t1 values
(1,300,'2017-10-25'),
(2,150,'2017-10-25'),
(3,550,'2017-10-27');
create table t2(id,amount,date);
insert into t2 values
(1,250,'2017-10-27'),
(2,410,'2017-10-28'),
(3,830,'2017-10-29');
select sum(amount_in) as amount_in, sum(amount_out) as amount_out, date
from (
select amount as amount_in, 0 as amount_out, date from t1
union all
select 0 as amount_in, amount as amount_out, date from t2
)
group by date;
That's a full outer join on the two aggregated tables:
select
coalesce(tin.ammount, 0) as ammount_in,
coalesce(tout.ammount, 0) as ammount_out,
date
from (select date, sum(ammount) as total from table_in group by date) tin
full outer join (select date, sum(ammount) as total from table_out group by date) tout
using (date);
This is works in MS sql server
SELECT SUM(amount_in) AS amount_in, SUM(amount_out) AS amount_out, date1
FROM (SELECT amount AS amount_in, 0 AS amount_out, date1
FROM t1
UNION ALL
SELECT 0 AS amount_in, amount AS amount_out, date1
FROM t2) AS derivedtbl_1
GROUP BY date1
So i have been scratching my head over this one,mostly because i am on access 2010 and most of the queries i have found on the internet have commands that do not work on access.
id name date qty created
====================================================
1 abc 01/2016 20 06/07/2016 11:00
2 abc 02/2016 20 06/07/2016 11:00
3 abc 03/2016 20 06/07/2016 11:00
4 abc 01/2016 30 06/07/2016 13:00
I need to pull out a recordset like this:
id name date qty created
====================================================
2 abc 02/2016 20 06/07/2016 11:00
3 abc 03/2016 20 06/07/2016 11:00
4 abc 01/2016 30 06/07/2016 13:00
the created field is just a timestamp, the date field is a "due date". basically i need to pull out the most recent qty for each name and date. the ID is unique so i can use it instead,if its easier.
By far i've got:
SELECT m1.date, m1.name, m1.created
FROM table AS m1 LEFT JOIN table AS m2 ON (m1.created < m2.created) AND
(m1.date = m2.date)
WHERE m2.created IS NULL;
but this one gives me only the most recent conflicted data, ie. the record n°4 in my example.i also need the other two records. any thoughts?
Try using NOT EXISTS() :
SELECT * FROM YourTable t
WHERE NOT EXISTS(SELECT 1 FROM YourTable s
WHERE t.date = s.date and s.created > t.created
AND t.name = s.name)
I think you are also missing a condition so I've added it:
and t.name = s.name
You didn't tag your RDBMS, if its SQL-Server/Oracle/Postgresql you can use ROW_NUMBER() :
SELECT s.date, s.name, s.created FROM (
SELECT t.*,
ROW_NUMBER() OVER(PARTITION BY t.date,t.name ORDER BY t.created DESC) as rnk
FROM YourTable t) s
WHERE s.rnk = 1
Try this:
SELECT m1.date, m1.name, m1.qty, m1.created
FROM table AS m1
JOIN (
SELECT date, name, MAX(created) AS created
FROM table
GROUP BY date, name
) AS m2 ON m1.date = m2.date AND m1.name = m2.name AND m1.created = m2.created
end date fee
-----------------
05-Sep-14 700
12-Sep-14 200
19-Sep-14 100
26-Sep-14 300
03-Oct-14 400
In the table shown here, I need to return enddate where cumulative sum of fee column is less than 1100 using SQL.
Example:
19-Sep-14 (700 + 200 + 100 < 1100)
SELECT TOP 1
t1.enddate,
t1.fee,
SUM(t2.fee) as cumulative_sum
FROM test t1
INNER JOIN tableName t2 on t1.enddate >= t2.enddate
GROUP BY t1.enddate, t1.fee
HAVING SUM(t2.fee) < 1100
ORDER BY t1.enddate DESC
Data sample
create view fees
as
select cast('05-Sep-14' as date) as end_date, 700 as fee
union all select '12-Sep-14', 200
union all select '19-Sep-14', 100
union all select '26-Sep-14', 300
union all select '03-Oct-14', 400
Solution
SELECT TOP 1
a.end_date,
SUM(b.fee) as cumulative
FROM fees a CROSS JOIN fees b
WHERE a.end_date >= b.end_date
GROUP BY a.end_date
HAVING SUM(b.fee) < 1100
ORDER BY end_date desc