SQL divide many records by day - mysql

my SQL table's struct is very simple,only contains 3 fields:
createDate(Date): time when record inserted;
title(String): title for record;
count(Integer32): count for record;
There 10w+ records in the table! Represents records inserted in one year:
Any day could inserted any number records(include 0 record)
So,How could I divide records by days???
eg: There 10 records in the table:
1. 2019-01-01 10:20:15 xxx
2. 2019-01-01 12:50:10 xxx
3. 2019-01-01 23:20:19 xxx
4. 2019-01-02 10:20:15 xxx
5. 2019-01-05 08:20:15 xxx
6. 2019-01-05 22:20:15 xxx
7. 2019-02-10 10:20:15 xxx
8. 2019-02-10 11:20:15 xxx
9. 2019-02-10 15:20:15 xxx
10. 2019-02-15 10:20:15 xxx
I want result : divide to 5 "collections"
collection "2019-01-01" (contain 3 records):
- 2019-01-01 10:20:15 xxx
- 2019-01-01 12:50:10 xxx
- 2019-01-01 23:20:19 xxx
collection "2019-01-02" (contain 1 record):
- 2019-01-02 10:20:15 xxx
collection "2019-01-05" (contain 2 records):
- 2019-01-05 08:20:15 xxx
- 2019-01-05 22:20:15 xxx
collection "2019-02-10" (contain 3 records):
- 2019-02-10 10:20:15 xxx
- 2019-02-10 11:20:15 xxx
- 2019-02-10 15:20:15 xxx
collection "2019-02-15" (contain 1 record):
- 2019-02-15 10:20:15 xxx

If my table schema is correct then this would be your possible solution.
GO
CREATE TABLE #tempRequestForMeList
(
createDate datetime,
title nvarchar(50),
[count] int
)
GO
insert into #tempRequestForMeList ( createDate, title, [count] )
values ( '2016-09-20 17:17:04.840', 'dd', 0 )
, ( '2016-09-20 17:17:04.840', 'dd', 1 )
, ( '2016-09-20 07:17:04.840', 'dd', 1 )
, ( '2016-09-20 05:17:04.840', 'dd', 1 )
, ( '2016-09-20 13:17:04.840', 'dd', 1 )
, ( '2016-09-19 12:17:04.840', 'dd', 1 )
, ( '2016-09-19 02:17:04.840', 'dd', 1 )
, ( '2016-09-19 01:17:04.840', 'dd', 1 )
, ( '2016-09-18 02:17:04.840', 'dd', 1 )
, ( '2016-09-18 03:17:04.840', 'dd', 1 )
, ( '2016-09-18 05:17:04.840', 'dd', 1 )
, ( '2016-09-18 07:17:04.840', 'dd', 1 )
GO
; with cte as (
select cast(createdate as date) as Date1, * from #tempRequestForMeList )
update dd set dd.[count] = ct.co from #tempRequestForMeList as dd inner join (select count(date1) as co, date1 from cte group by Date1) as ct on cast(dd.createDate as DATE) = ct.Date1
select * from #tempRequestForMeList --- if require count with each row
go
drop table #tempRequestForMeList
go
If this doesn't work then show your table schema and expected output.
Note: This is for SQL server

Try to use COUNT by PARTITION:
SELECT
t.*
, count( CONVERT(date, t.createDate)) OVER (PARTITION BY CONVERT(date, t.createDate)
ORDER BY CONVERT(date, t.createDate)) CountByDate
FROM
#tempRequestForMeList t
Let me show an example(Thanks to #DarkRob for sample data):
DECLARE #tempRequestForMeList TABLE
(
createDate DATETIME,
title NVARCHAR(50),
[count] INT
);
INSERT INTO #tempRequestForMeList
(
createDate,
title,
count
)
VALUES
('2016-09-20 17:17:04.840', 'dd', 0),
('2016-09-20 17:17:04.840', 'dd', 1),
('2016-09-20 07:17:04.840', 'dd', 1),
('2016-09-20 05:17:04.840', 'dd', 1),
('2016-09-20 13:17:04.840', 'dd', 1),
('2016-09-19 12:17:04.840', 'dd', 1),
('2016-09-19 02:17:04.840', 'dd', 1),
('2016-09-19 01:17:04.840', 'dd', 1),
('2016-09-18 02:17:04.840', 'dd', 1),
('2016-09-18 03:17:04.840', 'dd', 1),
('2016-09-18 05:17:04.840', 'dd', 1),
('2016-09-18 07:17:04.840', 'dd', 1),
('2016-10-20 17:17:04.840', 'dd', 0);
and query:
SELECT
t.*
, count( CONVERT(date, t.createDate)) OVER (PARTITION BY CONVERT(date, t.createDate)
ORDER BY CONVERT(date, t.createDate)) CountByDate
FROM
#tempRequestForMeList t
OUTPUT:
createDate title count CountByDate
2016-09-18 02:17:04.840 dd 1 4
2016-09-18 03:17:04.840 dd 1 4
2016-09-18 05:17:04.840 dd 1 4
2016-09-18 07:17:04.840 dd 1 4
2016-09-19 12:17:04.840 dd 1 3
2016-09-19 02:17:04.840 dd 1 3
2016-09-19 01:17:04.840 dd 1 3
2016-09-20 17:17:04.840 dd 0 5
2016-09-20 17:17:04.840 dd 1 5
2016-09-20 07:17:04.840 dd 1 5
2016-09-20 05:17:04.840 dd 1 5
2016-09-20 13:17:04.840 dd 1 5
2016-10-20 17:17:04.840 dd 0 1

Related

Calculate the period of validity of the price

I have a table with an item, its cost and the date it was added.
CREATE TABLE item_prices (
item_id INT,
item_name VARCHAR(30),
item_price DECIMAL(12, 2),
created_dttm DATETIME
);
INSERT INTO item_prices(item_id, item_name, item_price, created_dttm) VALUES
(1, 'spoon', 10.20 , '2023-01-01 01:00:00'),
(1, 'spoon', 10.20 , '2023-01-08 01:35:00'),
(1, 'spoon', 10.35 , '2023-01-14 15:00:00'),
(2, 'table', 40.00 , '2023-01-01 01:00:00'),
(2, 'table', 40.00 , '2023-01-03 11:22:00'),
(2, 'table', 41.00 , '2023-01-10 08:28:22'),
(1, 'spoon', 10.35 , '2023-01-28 21:52:00'),
(1, 'spoon', 11.00 , '2023-02-15 16:36:00'),
(2, 'table', 41.00 , '2023-02-16 21:42:11'),
(2, 'table', 45.20 , '2023-02-19 20:25:25'),
(1, 'spoon', 9.00 , '2023-03-02 14:50:00'),
(1, 'spoon', 9.00 , '2023-03-06 16:36:00'),
(1, 'spoon', 8.50 , '2023-03-15 12:00:00'),
(2, 'table', 30 , '2023-03-05 10:10:10'),
(2, 'table', 30 , '2023-03-10 15:45:00');
I need to create a new table with the following fields:
"item_id",
"item_name",
"item_price",
"valid_from_dt": date on which the price was effective (created_dttm price record)
"valid_to_dt": date until which this price was valid (created_dttm of the next record for this product "minus" one day)
I thought it might be possible to start by selecting days on which new entries are added with new prices with such a request:
SELECT item_id, item_name, item_price,
MIN(created_dttm) as dt
FROM table
GROUP BY item_price, item_id, item_name
that provides me this output:
The expected output is the following:
item_id
item_name
item_price
valid_from_dt
valid_to_dt
1
spoon
10.20
2023-01-01
2023-01-13
1
spoon
10.35
2023-01-14
2023-02-14
1
spoon
11.00
2023-02-15
2023-03-01
1
spoon
9.00
2023-03-02
2023-03-01
1
spoon
8.50
2023-03-15
2023-03-14
2
table
40.00
2023-01-01
2022-01-09
2
table
41.00
2023-01-10
2023-02-18
....
....
....
....
....
select distinct
item_id,
item_name,
first_value(item_price) over (partition by item_id order by created_dttm) as item_price,
min(created_dttm) over (partition by item_id ) as valid_from_dt,
max(created_dttm) over (partition by item_id ) as valid_to_dt
from item_prices
;
output:
item_id
item_name
item_price
valid_from_dt
valid_to_dt
1
spoon
10.20
2023-01-01 01:00:00
2023-03-15 12:00:00
2
table
40.00
2023-01-01 01:00:00
2023-03-10 15:45:00
see: DBFIDDLE
Your query is correct. It's only missing the next step:
retrieving the next "valid_from_dt" in the partition <item_id, item_name>, using the LEAD function
subtract 1 day from it
WITH cte AS (
SELECT item_id, item_name, item_price,
MIN(created_dttm) AS valid_from_dt
FROM item_prices
GROUP BY item_id, item_name, item_price
)
SELECT *,
LEAD(valid_from_dt) OVER(PARTITION BY item_id, item_name) - INTERVAL 1 DAY AS valid_to_dt
FROM cte
Check the demo here.

sql server 2008 running totals between 2 dates

I need to get running totals between 2 dates in my sql server table and update the records simultaneoulsy. My data is as below and ordered by date,voucher_no
DATE VOUCHER_NO OPEN_BAL DEBITS CREDITS CLOS_BAL
-------------------------------------------------------------------
10/10/2017 1 100 10 110
12/10/2017 2 110 5 105
13/10/2017 3 105 20 125
Now if i insert a record with voucher_no 4 on 12/10/2017 the output should be like
DATE VOUCHER_NO OPEN_BAL DEBITS CREDITS CLOS_BAL
------------------------------------------------------------------
10/10/2017 1 100 10 110
12/10/2017 2 110 5 105
12/10/2017 4 105 4 109
13/10/2017 3 109 20 129
I have seen several examples which find running totals upto a certain date but not between 2 dates or from a particular date to end of file
You should consider changing your database structure. I think it will be better to keep DATE, VOUCHER_NO, DEBITS, CREDITS in one table. And create view to calculate balances. In that case you will not have to update table after each insert. In this case your table will look like
create table myTable (
DATE date
, VOUCHER_NO int
, DEBITS int
, CREDITS int
)
insert into myTable values
('20171010', 1, 10, null),( '20171012', 2, null, 5)
, ('20171013', 3, 20, null), ('20171012', 4, 4, null)
And view will be
;with cte as (
select
DATE, VOUCHER_NO, DEBITS, CREDITS, bal = isnull(DEBITS, CREDITS) * case when DEBITS is null then -1 else 1 end
, rn = row_number() over (order by DATE, VOUCHER_NO)
from
myTable
)
select
a.DATE, a.VOUCHER_NO, a.DEBITS, a.CREDITS
, OPEN_BAL = sum(b.bal + case when b.rn = 1 then 100 else 0 end) - a.bal
, CLOS_BAL = sum(b.bal + case when b.rn = 1 then 100 else 0 end)
from
cte a
join cte b on a.rn >= b.rn
group by a.DATE, a.VOUCHER_NO, a.rn, a.bal, a.DEBITS, a.CREDITS
Here's another solution if you can not change your db structure. In this case you must run update statement each time after inserts. In both cases I assume that initial balance is 100 while recalculation
create table myTable (
DATE date
, VOUCHER_NO int
, OPEN_BAL int
, DEBITS int
, CREDITS int
, CLOS_BAL int
)
insert into myTable values
('20171010', 1, 100, 10, null, 110)
,( '20171012', 2, 110, null, 5, 105)
, ('20171013', 3, 105, 20, null, 125)
, ('20171012', 4, null, 4, null, null)
;with cte as (
select
DATE, VOUCHER_NO, DEBITS, CREDITS, bal = isnull(DEBITS, CREDITS) * case when DEBITS is null then -1 else 1 end
, rn = row_number() over (order by DATE, VOUCHER_NO)
from
myTable
)
, cte2 as (
select
a.DATE, a.VOUCHER_NO
, OPEN_BAL = sum(b.bal + case when b.rn = 1 then 100 else 0 end) - a.bal
, CLOS_BAL = sum(b.bal + case when b.rn = 1 then 100 else 0 end)
from
cte a
join cte b on a.rn >= b.rn
group by a.DATE, a.VOUCHER_NO, a.rn, a.bal
)
update a
set a.OPEN_BAL = b.OPEN_BAL, a.CLOS_BAL = b.CLOS_BAL
from
myTable a
join cte2 b on a.DATE = b.DATE and a.VOUCHER_NO = b.VOUCHER_NO

Calculate a Slide rate commission per agent with MySQL... AND in ON statement?

I have set up a sqlfiddle for this question : see here
I have an issue calculating a slide rate commission for Agents, based on their Sales (called NGR here).
The commission table is the following:
+----+------------+----------+----------+----------+--------+
| id | tier_min | tier_max | com_rate | dif_rate | agent |
+----+------------+----------+----------+----------+--------+
| 1 | 0 | 100000 | 0.15 | 0.15 | AGENT4 |
| 3 | 100000.001 | 200000 | 0.2 | 0.05 | AGENT4 |
| 4 | 200000.001 | 300000 | 0.25 | 0.05 | AGENT4 |
| 5 | 300000.001 | 500000 | 0.3 | 0.05 | AGENT4 |
| 6 | 500000.001 | 10000000 | 0.35 | 0.05 | AGENT4 |
+----+------------+----------+----------+----------+--------+
For example, if an Agent has $120000 sales in a period, he gets 15% from 0 to 100 000 (15000), 20% from the threshold 100000 to 200000 (20000*20%=4000), total 19 000
The mysql query detailed in the mysqlfiddle details the working formula:
sum((s.NGR - r.tier_min) * r.dif_rate) as SlideCom
And the final query looks like:
+--------+---------+------------+-------+----------+----------+
| Agent | APmonth | FirstMonth | NGR | FIXEDCOM | VARCOM2 |
+--------+---------+------------+-------+----------+----------+
| AGENT1 | 3 | 0 | 16802 | 0 | 2520.327 |
| AGENT2 | 17 | 2 | 7926 | 60 | 1188.975 |
| AGENT3 | 3 | 0 | 6541 | 0 | 981.15 |
| AGENT4 | 4 | 0 | 5513 | 0 | 826.95 |
| AGENT5 | 1 | 0 | 3 | 0 | 0.6 |
| AGENT6 | 1 | 0 | 1 | 0 | 0.21 |
+--------+---------+------------+-------+----------+----------+
My issues:
I cannot fix the issue where i need EACH agent to have its specific sliding scale of commission, and relate the AGENT field in the Commissions table to its corresponding Agent's Sales (NGR). I tried to modified the query adding to
JOIN commissions r ON r.tier_min <= s.NGR AND s.Agent= a.Agent
but it does not work.
Any help on this issue would be a great help since I have been trying to do this for a while on my own with my limited Mysql skills;)
Thanks!
full data in case on sql fiddle issue:
CREATE TABLE commissions
(`id` int, `tier_min` double, `tier_max` double, `com_rate` double, `dif_rate` double, `agent` varchar(50))
;
INSERT INTO commissions
(`id`, `tier_min`, `tier_max`, `com_rate`, `dif_rate`, `agent`)
VALUES
(1, 0, 100000, .15, .15, 'AGENT4'),
(3, 100000.001, 200000, .2, .05, 'AGENT4'),
(4, 200000.001, 300000, .25, .05, 'AGENT4'),
(5, 300000.001, 500000, .3, .05, 'AGENT4'),
(6, 500000.001, 10000000, .35, .05, 'AGENT4')
;
CREATE TABLE Online_customer_activity_v2
(`id` int, `Date` datetime, `Customers` varchar(100), `Agent` varchar(100), `Real_Money` int, `_Bonuses` int, `Total_Bets` int, `Total_Win_Loss` int)
;
INSERT INTO Online_customer_activity_v2
(`id`, `Date`, `Customers`, `Agent`, `Real_Money`, `_Bonuses`, `Total_Bets`, `Total_Win_Loss`)
Values
(6813, '2017-01-01 00:00:00', 'KingOfPop', 'AGENT2',101000,1000,4000,100500),
(6814, '2017-01-01 00:00:00', 'Serena77', 'AGENT4',130000,1000,514500,120000),
(6815, '2017-01-01 00:00:00', 'KerymNY', 'AGENT3',376,0,1267.65,375.93),
(6816, '2017-01-01 00:00:00', 'whatthelol', 'AGENT1',130,0,6233.5,119.4993),
(6817, '2017-01-01 00:00:00', 'Noukashi', 'AGENT2',0,0,343.4,49.8),
(6818, '2017-01-01 00:00:00', 'SeaSunBeach', 'AGENT2',30,0,654.5,30),
(6819, '2017-01-01 00:00:00', 'Rizo_090', 'AGENT3',400,0,2675,-1165),
(6820, '2017-01-02 00:00:00', 'Rizo_090', 'AGENT3',7900,1200,140168,30199)
;
CREATE TABLE Online_playerdatabase_v2
(`id` int, `Player` varchar(50), `Agent` varchar(50), `Sign_Up_Date` varchar(12), `First_Deposit_Date` varchar(18))
;
INSERT INTO Online_playerdatabase_v2
(`id`, `Player`, `Agent`, `Sign_Up_Date`, `First_Deposit_Date`)
VALUES
(75, 'KerymNY', 'AGENT3', '2015-02-21', '2015-02-26'),
(137, 'Rizo_090', 'AGENT3', '2015-10-23', '2015-10-23'),
(286, 'KingOfPop', 'AGENT2', '2016-10-03', '2016-12-21'),
(6, 'Noukashi', 'AGENT2', '2016-07-21', '2016-07-22'),
(294, 'Serena77', 'AGENT4', '2016-10-09', '2017-01-02'),
(160, 'whatthelol', 'AGENT1', '2015-03-01', '2015-03-05'),
(360, 'SeaSunBeach', 'AGENT2', '2016-04-18', '2016-04-18')
;
SELECT
a.Agent ,
t2.APmonth ,
COALESCE(t8.FirstMonth , 0) AS FirstMonth ,
TRUNCATE(a.NGR , 0) AS NGR ,
COALESCE(t8.FirstMonth , 0) * 30 AS FIXEDCOM ,
COALESCE(yy.SlideCom , 0) AS VARCOM2 ,
TRUNCATE(
COALESCE(t8.FirstMonth , 0) * 30 + COALESCE(yy.SlideCom , 0) ,
0
) AS totalCOM
FROM
(
SELECT
Online_customer_activity_v2.Agent ,
sum(
Online_customer_activity_v2._Bonuses
) AS BONUS ,
sum(
Online_customer_activity_v2.Total_Win_Loss
) - sum(
Online_customer_activity_v2._Bonuses
) AS NGR
FROM
Online_customer_activity_v2
WHERE
(
Online_customer_activity_v2.Date BETWEEN '2017-01-01'
AND '2017-01-12'
AND Agent <> 'NOAGENT'
)
GROUP BY
Online_customer_activity_v2.Agent
) a
LEFT JOIN(
SELECT
Agent ,
count(First_Deposit_Date) AS FirstMonth
FROM
Online_playerdatabase_v2
WHERE
Online_playerdatabase_v2.First_Deposit_Date BETWEEN '2017-01-01'
AND '2017-01-12'
GROUP BY
Agent
) t8 ON a.Agent = t8.Agent
LEFT JOIN(
SELECT
Online_customer_activity_v2.Agent ,
COUNT(DISTINCT(Customers)) AS APmonth
FROM
Online_customer_activity_v2
WHERE
(
Online_customer_activity_v2.Date BETWEEN '2017-01-01'
AND '2017-01-12'
AND Agent <> 'NOAGENT'
)
AND Online_customer_activity_v2.Total_Bets > 0
GROUP BY
Agent
) AS t2 ON a.Agent = t2.Agent
LEFT JOIN(
SELECT
s.Agent ,
sum((s.NGR - r.tier_min) * r.dif_rate) SlideCom
FROM
(
SELECT
Date ,
Online_customer_activity_v2.Agent ,
sum(
Online_customer_activity_v2.Total_Win_Loss
) - sum(
Online_customer_activity_v2._Bonuses
) AS NGR
FROM
Online_customer_activity_v2
WHERE
Agent <> 'NOAGENT'
AND (Date BETWEEN '2017-01-01'
AND '2017-01-12')
GROUP BY
Agent ,
date_format(Date , '%Y-%m')
) s
JOIN commissions r ON r.tier_min <= s.NGR
GROUP BY
Agent
) yy ON a.Agent = yy.Agent
ORDER BY
NGR DESC;
I think this is you are looking for:
SeLeCt t5.Agent,t6.APmonth,t6.FirstMonth,t5.NGR,t5.toRate,t5.comm FrOm
(
SELECT t2.Agent,t2.NGR,ROUND(sum(t2.toRate),2) AS 'toRate',ROUND(sum(t2.comm),2) AS 'comm' FROM
(
select t1.Agent,t1.NGR,if(t1.NGR-c.tier_min>0,
if(t1.NGR>c.tier_max,c.tier_max-c.tier_min,t1.NGR-c.tier_min),
0) as 'toRate',
if(t1.NGR-c.tier_min>0,
if(t1.NGR>c.tier_max,c.tier_max-c.tier_min,t1.NGR-c.tier_min),
0)*c.com_rate as 'comm'
from myDB.commissions c ,
(
SELECT ocav2.Agent, sum(ocav2.Total_Win_Loss - ocav2._Bonuses) as 'NGR'
FROM myDB.Online_customer_activity_v2 ocav2
GROUP BY ocav2.Agent
) t1
where c.agent = t1.Agent
) t2
GROUP BY t2.Agent
) t5 LeFt JoIn
(
select t3.Agent,t3.APmonth,if(t4.FirstMonth is null,0,t4.FirstMonth) as 'FirstMonth' from
(
SELECT oca.Agent,COUNT(DISTINCT(oca.Customers)) AS 'APmonth'
FROM Online_customer_activity_v2 oca
WHERE oca.Total_Bets>0 AND oca.Date BETWEEN '2017-01-01' AND '2017-01-12'
GROUP BY oca.Agent
) t3 LEFT JOIN
(
SELECT
opv2.Agent ,
count(opv2.First_Deposit_Date) AS 'FirstMonth'
FROM
Online_playerdatabase_v2 opv2
WHERE
opv2.First_Deposit_Date BETWEEN '2017-01-01' AND '2017-01-12'
GROUP BY
opv2.Agent
) t4
on t3.Agent=t4.Agent
) t6 On t5.Agent=t6.Agent
;
Remember change "myDB" by your database
Given
drop table if exists t;
create table t( id int, tier_min int, tier_max int, com_rate decimal(10,2), dif_rate decimal(10,2), agent varchar(10));
truncate table t;
insert into t values
( 1 , 0 , 100000, 0.15 , 0.15 , 'AGENT4'),
( 3 , 100000.001 , 200000 , 0.2 , 0.05 , 'AGENT4'),
( 4 , 200000.001 , 300000 , 0.25 , 0.05 , 'AGENT4'),
( 5 , 300000.001 , 500000 , 0.3 , 0.05 , 'AGENT4'),
( 6 , 500000.001 , 10000000 , 0.35 , 0.05 , 'AGENT4'),
( 7 , 0 , 10000 , 0.15 , 0.15 , 'AGENT1'),
( 8 , 10000.001 , 15000 , 0.2 , 0.05 , 'AGENT1'),
( 9 , 15000.001 , 20000 , 0.3 , 0.05 , 'AGENT1'),
( 10 , 0 , 100000, 0.15 , 0.15 , 'AGENT6'),
( 11 , 100000.001 , 200000 , 0.2 , 0.05 , 'AGENT6'),
( 12 , 200000.001 , 300000 , 0.25 , 0.05 , 'AGENT6'),
( 13 , 300000.001 , 500000 , 0.3 , 0.05 , 'AGENT6'),
( 14 , 500000.001 , 10000000 , 0.35 , 0.05 , 'AGENT6')
;
drop table if exists agent;
create table agents ( Agent varchar(10) , APmonth int, FirstMonth int, NGR int, FIXEDCOM int, VARCOM2 decimal(10,2));
truncate table agents;
insert into agents values
( 'AGENT1' , 3 , 0 , 16802 , 0 , 2520.327),
( 'AGENT2' , 17 , 2 , 7926 , 60 , 1188.975),
( 'AGENT3' , 3 , 0 , 6541 , 0 , 981.15),
( 'AGENT4' , 4 , 0 , 5513 , 0 , 826.95),
( 'AGENT5' , 1 , 0 , 3 , 0 , 0.6),
( 'AGENT6' , 1 , 0 , 750000, 0 , 0.21);
Try this
select u.sagent, u.ngr,
u.amt1+u.amt2+u.amt3+u.amt4+u.amt5 as Commamt,
u.com1+u.com2+u.com3+u.com4+u.com5 as Comm
from
(
SELECT T.SAGENT,T.NGR,t.comrate1,
if(t.ngr <= t.maxtier1 , t.ngr ,t.maxtier1) amt1,
ifnull(t.comrate1 * if(t.ngr <= t.maxtier1 , t.ngr ,t.maxtier1),0) com1,
t.comrate2,
if(t.ngr >= t.mintier2 and t.ngr <= t.maxtier2, t.ngr - t.maxtier1,if(t.ngr > t.mintier3,t.maxtier2 - t.maxtier1,0)) amt2,
ifnull(t.comrate2 * if(t.ngr >= t.mintier2 and t.ngr <= t.maxtier2, t.ngr - t.maxtier1,if(t.ngr > t.mintier3,t.maxtier2 - t.maxtier1,0)),0) com2,
t.comrate3,
if(t.ngr >= t.mintier3 and t.ngr <= t.maxtier3, t.ngr - t.maxtier2,if(t.ngr > t.mintier4,t.maxtier3 - t.maxtier2,0)) amt3,
ifnull(t.comrate3 * if(t.ngr >= t.mintier3 and t.ngr <= t.maxtier3, t.ngr - t.maxtier2,if(t.ngr > t.mintier4,t.maxtier3 - t.maxtier2,0)),0) com3,
t.comrate4,
if(t.ngr >= t.mintier4 and t.ngr <= t.maxtier4, t.ngr - t.maxtier3,if(t.ngr > t.mintier5,t.maxtier4 - t.maxtier3,0)) amt4,
ifnull(t.comrate4 * if(t.ngr >= t.mintier4 and t.ngr <= t.maxtier4, t.ngr - t.maxtier3,if(t.ngr > t.mintier5,t.maxtier4 - t.maxtier3,0)),0) com4,
t.comrate5,
if(t.ngr >= t.mintier5 and t.ngr <= t.maxtier5, t.ngr - t.maxtier4,if(t.ngr > 9999999999,t.maxtier5 - t.maxtier4,0)) amt5,
ifnull(t.comrate5 * if(t.ngr >= t.mintier5 and t.ngr <= t.maxtier5, t.ngr - t.maxtier4,if(t.ngr > 9999999999,t.maxtier5 - t.maxtier4,0)),0) com5
FROM
(
select s.agent SAGENT,a.*,
max(case when s.rn = 1 then s.tier_min end) mintier1,
max(case when s.rn = 1 then s.tier_max end) maxtier1,
max(case when s.rn = 1 then s.com_rate end) comrate1,
max(case when s.rn = 2 then s.tier_min end) mintier2,
max(case when s.rn = 2 then s.tier_max end) maxtier2,
max(case when s.rn = 2 then s.com_rate end) comrate2,
max(case when s.rn = 3 then s.tier_min end) mintier3,
max(case when s.rn = 3 then s.tier_max end) maxtier3,
max(case when s.rn = 3 then s.com_rate end) comrate3,
max(case when s.rn = 4 then s.tier_min end) mintier4,
max(case when s.rn = 4 then s.tier_max end) maxtier4,
max(case when s.rn = 4 then s.com_rate end) comrate4,
max(case when s.rn = 5 then s.tier_min end) mintier5,
max(case when s.rn = 5 then s.tier_max end) maxtier5,
max(case when s.rn = 5 then s.com_rate end) comrate5
from
(
select t.*,
if (t.agent <> #p ,#rn:=1,#rn:=#rn+1) rn,
#p:=t.agent
from (select #rn:=0,#p:='') rn,t
order by t.agent, t.id
) s
join agents a on a.agent = s.agent
group by s.agent
) T
) u
Note I am assuming a max number of rates as 5
The sub query s allocates a row number to each rate per agent (1-5) which is then joined and pivoted to create 1 row per agent.The sub query t then works out the amount that falls into each commission band and the value of the commission. The outer query then simply totals the amounts that fall into each band as a cross check and the final commission amount.

Condition on multiple values in the same column in SQL

Firstly, thanks in advance for helping. This will be my first question on SOF.
I have the following SQL database tables.
qualificationTable:
QualId studentNo CourseName Percentage
1 1 A 91
2 1 B 81
3 1 C 71
4 1 D 61
5 2 A 91
6 2 B 81
7 2 C 71
8 2 D 59
testTable:
TestId studentNo testNo Percentage dateTaken
1 1 1 91 2016-05-02
2 1 2 41 2015-05-02
3 1 3 71 2016-04-02
4 1 1 95 2014-05-02
5 1 2 83 2016-01-02
6 1 3 28 2015-05-02
7 2 1 90 2016-05-02
8 2 2 99 2016-05-02
9 2 3 87 2016-05-02
I have the minimum percentages specified for courses A, B, C and D individually. I need to search for students, meeting the minimum criteria for ALL the courses.
Part-2:
That student should also match the criteria (minimum percentages specified individually for the three tests- 1,2 and 3) in testTable.
In other words, if a student matches the minimum criteria (percentage) specified individually for all the courses, he should be selected. Now, same goes for the testTable, that particular student (who got selected in qualificationTable) should have the minimum criteria (percentage) specified individually for the three tests (1,2 and 3) in testNo column.
Edit:
I have updated the testTable, now there are multiple tests for a particular student. I need to check if the student meets the minimum required percentage specified for all the 3 tests, however, only the most recently taken test in each no (1,2 and 3) should count. If the student does not meet the minimum criteria specified for the most recent test, he should not be included.
Test Case:
Minimum qualification percentage required:
Course A: 90 Course B: 80 Course C: 70 Course D: 60
Minimum tests percentage required:
Test 1: 90 Test 2: 80 Test 3: 70
Expected Output
studentNo
1
Cheers
I've just figured it out for your sample data and Test Case:
Minimum qualification percentage required:
Course A: 90 Course B: 80 Course C: 70 Course D: 60
Minimum tests percentage required:
Test 1: 90 Test 2: 80 Test 3: 70
Try this, may help for you;)
SQL Fiddle
MySQL Schema:
CREATE TABLE qualificationTable
(`QualId` int, `studentNo` int, `CourseName` varchar(1), `Percentage` int)
;
INSERT INTO qualificationTable
(`QualId`, `studentNo`, `CourseName`, `Percentage`)
VALUES
(1, 1, 'A', 91),
(2, 1, 'B', 81),
(3, 1, 'C', 71),
(4, 1, 'D', 61),
(5, 2, 'A', 91),
(6, 2, 'B', 81),
(7, 2, 'C', 71),
(8, 2, 'D', 50)
;
CREATE TABLE testTable
(`TestId` int, `studentNo` int, `testNo` int, `Percentage` int)
;
INSERT INTO testTable
(`TestId`, `studentNo`, `testNo`, `Percentage`)
VALUES
(1, 1, 1, 91),
(2, 1, 2, 81),
(3, 1, 3, 71),
(4, 2, 1, 80),
(5, 2, 2, 99),
(6, 2, 3, 87)
;
Query 1:
select t1.studentNo
from
(
select studentNo from qualificationTable
where (CourseName = 'A' and Percentage >= 90)
or (CourseName = 'B' and Percentage >= 80)
or (CourseName = 'C' and Percentage >= 70)
or (CourseName = 'D' and Percentage >= 60)
group by studentNo
having count(1) = 4
) t1 join
( select studentNo from testTable
where (testNo = '1' and Percentage >= 90)
or (testNo = '2' and Percentage >= 80)
or (testNo = '3' and Percentage >= 70)
group by studentNo
having count(1) = 3
) t2 on t1.studentNo = t2.studentNo
I just pick t1 one of these two subquery to explain how it works:
GROUP BY can get us a result like this,
| studentNo |
|-----------|
| 1 |
| 2 |
COUNT will get us total count of each group, for your sample data, studentNo(1) is 4, studentNo(2) is 4 as well, but we also has where clause here, so by these criteria, we can find which matched are following record,
(1, 1, 'A', 91),
(2, 1, 'B', 81),
(3, 1, 'C', 71),
(4, 1, 'D', 61),
(5, 2, 'A', 91),
(6, 2, 'B', 81),
(7, 2, 'C', 71)
And this means COUNT will give us studentNo(1) to 4, studentNo(2) to 3, so when mysql run having count(1) = 4, this subquery only return us studentNo(1)
Subquery t2 works like that, and when join these two subquery by studentNo, it will return what you expected result.
Results:
| studentNo |
|-----------|
| 1 |
Edited:
select t1.studentNo
from
(
select studentNo from qualificationTable
where (CourseName = 'A' and Percentage >= 90)
or (CourseName = 'B' and Percentage >= 80)
or (CourseName = 'C' and Percentage >= 70)
or (CourseName = 'D' and Percentage >= 60)
group by studentNo
having count(1) = 4
) t1 join
( select studentNo
from (
select *
from testTable
where (testNo, dateTaken) in (
select testNo, Max(dateTaken) from testTable group by testNo
)
) tmp
where (testNo = '1' and Percentage >= 90)
or (testNo = '2' and Percentage >= 80)
or (testNo = '3' and Percentage >= 70)
group by studentNo
having count(1) = 3
) t2 on t1.studentNo = t2.studentNo
First find students who does not qualify the minimum percentage.
select distinct studentNo
from stdqualificationmaster
where case when CourseName='A' and Percentage<90 then 'F'
when CourseName='B' and Percentage<80 then 'F'
when CourseName='C' and Percentage<70 then 'F'
when CourseName='D' and Percentage<60 then 'F'
end='F'
As a second step we can use above unqualified students result set as filter for required result set.
select * from stdqualificationmaster where studentNo not in
( select distinct studentNo
from stdqualificationmaster
where case when CourseName='A' and Percentage<90 then 'F'
when CourseName='B' and Percentage<80 then 'F'
when CourseName='C' and Percentage<70 then 'F'
when CourseName='D' and Percentage<60 then 'F'
end='F')

Get Max in a Group based on a condition

ProjID Dno RNo Status DateApproved
100 1 1 Initiated 2014-12-31 09:15:58.000
100 1 1 Approved 2015-01-31 09:15:58.000
100 1 1 Approved 2015-02-01 09:15:58.000
100 1 1 Approved 2015-05-28 09:15:58.000
100 1 1 Approved 2015-06-20 09:15:58.000
101 1 1 Approved 2014-12-31 09:15:58.000
101 1 1 Approved 2015-01-31 09:15:58.000
101 1 1 Approved 2015-02-01 09:15:58.000
101 1 1 Approved 2015-05-28 09:15:58.000
101 1 1 Approved 2015-08-20 09:15:58.000
In the above example i have to get max(Dateapproved) as Dateapproved for each projectid.
if all the revision Status are approved in a particular group for eg :project id=101 has all rows in its group having a status as Approved so i have to get the max date : '2015-08-20 09:15:58.000'.But for Projectid=100 one status is still in Initiated State so we have to show Null as Dateapproved .
Thanks in Advance
My output should be like:
ProjId Dno Rno DateApproved
100 1 1 NUll
101 1 1 2015-08-20 09:15:58.000
Example code:
Create table #temp(
ProjectID varchar(35),
Documentno int,
Revisionno int,
Status varchar(35),
DateApproved Datetime)
insert into #temp values ( '100', 1, 1, 'Initiated','2014-12-31 09:15:58')
insert into #temp values ( '100', 1, 1, 'Approved','2015-01-31 09:15:58 ')
insert into #temp values ( '100', 1, 1, 'Approved','2015-02-01 09:15:58 ')
insert into #temp values ( '100', 1, 1, 'Approved','2015-05-28 09:15:58 ')
insert into #temp values ( '100', 1, 1, 'Approved','2015-06-20 09:15:58 ')
insert into #temp values ( '101', 1, 1, 'Approved','2014-12-31 09:15:58 ')
insert into #temp values ( '101', 1, 1, 'Approved','2015-01-31 09:15:58 ')
insert into #temp values ( '101', 1, 1, 'Approved','2015-02-01 09:15:58 ')
insert into #temp values ( '101', 1, 1, 'Approved','2015-05-28 09:15:58 ')
insert into #temp values ( '101', 1, 1, 'Approved','2015-08-20 09:15:58 ')
select * from #temp
Try this:
SELECT T.ProjectID,
Documentno as Dno,
Revisionno as RNo,
CASE WHEN SUM(CASE WHEN T.Status <> 'Approved' THEN 1 ELSE 0 END) = 0
THEN Max(T.DateApproved) ELSE NULL
END as DateApproved
from #temp T
GROUP BY T.ProjectId, Documentno , Revisionno
This gives the following output when run against your test data:
PROJECT ID DNo TNo DateApproved
100 1 1 NULL
101 1 1 2015-08-20 09:15:58.000
You can do this with a case statement and a conditional aggregate. Get the count of statuses that are not Approved using COUNT(NULLIF(Status, 'Approved')). If this is 0 then get the max date approved:
SELECT ProjectID,
DateApproved = CASE WHEN COUNT(NULLIF(Status, 'Approved')) = 0 THEN MAX(DateApproved) END
FROM #Temp
GROUP BY ProjectID;