I am getting the sum of all the rows in registration table. Table structure looks like this:
row_id row_registration_fee row_amount row_class row_user_id
1 200 1000 18 1
2 200 2510 18 1
3 0 1600 19 2
4 0 1500 19 1
5 200 1254 19 3
6 200 3000 19 1
7 200 2000 19 1
8 0 100 20 1
9 0 300 20 2
A user can have multiple registration fee. And I need to get the sum of all the row_registration_fee by row_class. The result should be like this:
row_registration_fee row_class
200 18
400 19
0 20
My select :
SELECT (COUNT(DISTINCT(row_user_id))* 200) as 'fee'
FROM registration
WHERE row_registration_fee > 0
GROUP BY row_class
Is there a better query here that can give a result like the above sample?
The result will be displayed in table rows using foreach loop in PHP. As of now, it will only give me two results for the registration fee, the row_class 18 and row_class 19 it excludes the row_class 20 because it only selects the user with a fee.
Additional explanation: The user with 2 or more registration fees should count only as one if the user has a total of 400 fees it should sum only 200.
Another approach might be to find the most recent row_id. In this case I have altered the data so that the first entry appears to be an error (fee = 300) followed by the second entry for the correct amount .
drop table if exists t;
create table t(
row_id int,row_registration_fee int,row_amount int, row_class int, row_user_id int);
insert into t values
(1 , 300 , 1000 , 18 , 1),
(2 , 200 , 2510 , 18 , 1),
(3 , 0 , 1600 , 19 , 2),
(4 , 0 , 1500 , 19 , 1),
(5 , 200 , 1254 , 19 , 3),
(6 , 200 , 3000 , 19 , 1),
(7 , 200 , 2000 , 19 , 1),
(8 , 0 , 100 , 20 , 1),
(9 , 0 , 300 , 20 , 2)
;
select sum(row_registration_fee),row_class
from
(
select t.row_class,t.row_registration_fee
from t
where t.row_id = (select max(row_id) from t t1 where t1.row_user_id = t.row_user_id and t1.row_class = t.row_class)
) a
group by row_class;
+---------------------------+-----------+
| sum(row_registration_fee) | row_class |
+---------------------------+-----------+
| 200 | 18 |
| 400 | 19 |
| 0 | 20 |
+---------------------------+-----------+
3 rows in set (0.00 sec)
To get those expected results then it seems to me that you first need to get the unique records per (row_registration_fee, row_class, row_user_id) tupple.
You can use a sub-query with a DISTINCT for that.
Then sum the row_registration_fee.
SELECT
SUM(row_registration_fee) as fee,
row_class
FROM
(
SELECT DISTINCT row_class, row_user_id, row_registration_fee
FROM registration
) q
GROUP BY row_class
Or via a GROUP BY and get the MAX fee.
SELECT
SUM(max_fee) as fee,
row_class
FROM
(
SELECT
row_class, row_user_id,
MAX(row_registration_fee) as max_fee
FROM registration
GROUP BY
row_class, row_user_id
) q
GROUP BY row_class
But to fix your current query, you could remove that WHERE clause.
And then use a CASE WHEN to return NULL on a zero row_registration_fee.
Because a count by value doesn't count the NULL's.
SELECT
COUNT(DISTINCT CASE WHEN row_registration_fee = 0 THEN row_user_id END) * 200 as fee,
row_class
FROM registration
GROUP BY row_class
You need to group by two columns and take sum:
select row_class, sum(row_registration_fee)
from registration
group by row_class, row_user_id
SELECT SUM(row_registration_fee), row_class, row_user_id
FROM registration
WHERE row_registration_fee > 0
GROUP BY row_class, row_user_id;
Yeah, group by two columns you can get per class and user.
Related
I have 2 queries where I group by week, by quarter and year using added_on, the problem comes in when I try to combine the queries since the first query weeks are from 1,2,3,4,5,....,25, it has transactions in every week of the year and the second query is 1,4,5,8,15,25 because it does not have transactions on some weeks and I need for both to have 1,2,3,4,5,6,7,...,25 is there any way to achieve this?
transaction table
id
value
added_on
currency_id
1
100
2020/01/20
2
320
2020/2/10
currency table
id
type
1
USD
2
EUR
My query is looking like this
SELECT
week_usd,
week_eur,
total_usd,
total_eur,
quarter_year
FROM
(SELECT
WEEK(transaction.added_on) AS week_usd,
SUM(transaction.value) AS total_usd,
CONCAT(QUARTER(transaction.added_on)," ", YEAR(transaction.added_on)) AS quarter_year
FROM transaction
JOIN currency ON transaction.currency_id = currency.id
WHERE
currency.type = 'USD'
GROUP BY 1,3
) AS table1,
(SELECT
WEEK(transaction.added_on) AS week_eur,
SUM(transaction.value) AS total_eur,
CONCAT(QUARTER(transaction.added_on)," ", YEAR(transaction.added_on)) AS quarter_year
FROM transaction
JOIN currency ON transaction.currency_id = currency.id
WHERE
currency.type = 'EUR'
GROUP BY 1,3
) AS table2
The problem with my query is that it will display like this
week_usd
week_eur
total_usd
total_eur
quarter_year
0
1
100
150
1 2020
1
1
100
150
1 2020
2
1
100
150
1 2020
3
1
100
150
1 2020
4
1
100
150
1 2020
5
1
100
150
1 2020
6
1
100
150
1 2020
7
1
100
150
1 2020
8
1
100
150
1 2020
You need first to create unique list of dates before getting joins of totals:
Select date_list.quarter_year
, date_list.week
, USD.total_usd
, EUR.total_eur
from
( select distinct CONCAT(QUARTER(transaction.added_on)," ", YEAR(transaction.added_on)) AS quarter_year
, WEEK(transaction.added_on) week
from transaction
) as date_list
Left Join (
select CONCAT(QUARTER(transaction.added_on)," ", YEAR(transaction.added_on)) AS quarter_year
, WEEK(transaction.added_on) week
, SUM(transaction.value) AS total_usd
from transaction
join currency on transaction.currency_id = currency.id
where currency.type = 'USD'
group by 1,2
) as USD on date_list.quarter_year = USD.quarter_year and date_list.week = USD.week
Left Join (
select CONCAT(QUARTER(transaction.added_on)," ", YEAR(transaction.added_on)) AS quarter_year
, WEEK(transaction.added_on) week
, SUM(transaction.value) AS total_eur
from transaction
join currency on transaction.currency_id = currency.id
where currency.type = 'EUR'
group by 1,2
) as EUR on date_list.quarter_year = EUR.quarter_year and date_list.week = EUR.week ;
I am having a dilemma from comparing my tables.
My problem is, I want to get each sum, which depends on the pricing. Here is the table.
Main table
main_id main_price main_date_created
25 8.5 2019-08-16
26 11.5 2019-08-01
Total table
id main_id total_price date_generated
1 25 10 2019-08-16
2 25 10 2019-08-17
3 25 10 2019-08-18
4 25 10 2019-08-19
5 25 10 2019-08-20
6 25 10 2019-08-21
7 26 20 2019-08-01
8 26 5 2019-08-02
9 26 5 2019-08-03
10 26 10 2019-08-04
Price History table
id main_id changed_main_price price_date_changed
1 25 15 2019-08-18
2 26 20 2019-08-03
I don't know if there is a way to do this just by using MySQL, what I am trying to achieve is, the Total table will be sum by MONTH and YEAR and will be multiplied by their designated price that depends on the date whether if the price has changed or not . the SUM will from each month will be generated by multiplying with the main price in the Main table but if the price had changed from its original price which it is on the Price history table
The output should be like this if the conditional is possible:
id main_id total_price price_generated (which is the prices) date
1 25 170 (10+10*8.5) 8.5
2 25 610 (10+10+10+10*15) 15
3 26 287.5 (20+5*11.5) 11.5
4 26 300 (5+10*20) 20
Here is my existing query,
SELECT m.main_id
, m.main_price
, SUM(t.total_price) total_generated
, t.date_generated
FROM main m
INNER JOIN total t
ON m.main_id = t.main_id
GROUP
BY MONTH(t.date_generated);
I know that my query is not enough, and I still don't know if my idea is really possible :(.
I racked my brain. hahaha Is this you're after?
SELECT pricelist.id, pricelist.price, SUM(t.total_price), SUM(t.total_price) * pricelist.price,
year( pricelist.latestdate), month(pricelist.latestdate),
year( t.total_date_generated), month(t.total_date_generated)
from totaltable as t
LEFT JOIN (
(
select main_id as id, main_price as price, main_date_created as latestdate
from maintable
)
UNION ALL
(
select total_main_id, changed_main_price , price_date_changed
from pricehistorytable
)
) as pricelist on pricelist.id = t.total_main_id
GROUP BY pricelist.id , t.total_price, pricelist.price,
year( pricelist.latestdate), month(pricelist.latestdate),
year( t.total_date_generated), month(t.total_date_generated) ;
This question already has answers here:
What's the most efficient way to select the last n rows in a table without changing the table's structure?
(8 answers)
Closed 4 years ago.
I want to make a query that retrieve data from two table i.e one is purchase and another is issue.
both tables have same fields i.e icode,qty,rate,purdate and issuedate.
query of purchase is:-SELECT Dry_Purchase.Icode, Sum(Dry_Purchase.Qty) AS SumOfQty, Dry_Purchase.Rate
FROM Dry_Purchase
WHERE (((Dry_Purchase.PurDate) Between DateSerial(Year(Date()),(Month(Date())-1),21) And DateSerial(Year(Date()),Month(Date()),20)))
GROUP BY Dry_Purchase.Icode, Dry_Purchase.Rate;
output of purchase query is:
Icode SumOfQty Rate
11 10 13.5
11 39.5 14
19 75 79.75
19 22 80
21 54 87.45
23 15 218
24 10.5 650
8 79 33.25
8 13 34
query of issue is :- SELECT Dry_Expense.Icode, Sum(Dry_Expense.Qty) AS SumOfQty, Dry_Expense.Rate
FROM Dry_Expense
WHERE (((Dry_Expense.ExpDate) Between DateSerial(Year(Date()),(Month(Date())-1),21) And DateSerial(Year(Date()),Month(Date()),20)))
GROUP BY Dry_Expense.Icode, Dry_Expense.Rate;
output of this query is
Icode SumOfQty Rate
11 11.55 13
11 8.55 13.5
11 10.8 14
19 2.35 80
21 54 87.45
8 15.9 33.25
after combining above both query the output should like this
rptdate icode opening recd issued closingbal rate
19/09/18 11 0 10 8.550 1.450 13.50
19/09/18 11 0 39.5 10.800 28.700 14.00
19/09/18 19 0 75 0.000 75 79.75
19/09/18 19 0 22 2.350 72.650 80.00
19/09/18 21 0 54 54 0 87.45
19/09/18 23 0 15 0 15 218.00
19/09/18 24 0 10.5 0 10.500 650.00
19/09/18 8 0 79.0 15.900 63.100 33.25
19/09/18 8 0 13.0 0 13.000 34.00
19/09/18 8 11.550 0 11.550 0 13.00
please help me how to make query for this output
i am trying this query
SELECT A.icode,A.qty,A.rate,A.recd as recd,B.Issued as Issue
FROM (SELECT icode,rate,purdate,SUM(Abs(qty)) AS recd
FROM Dry_Purchase GROUP BY icde,rate ) A,
(SELECT icode,rate,expdate,(SUM(Abs(qty)) AS Issue
FROM Dry_Expense GROUP BY icode,rate) B
WHERE A.icode=B.icode AND A.rate=B.rate AND
(A.purdate Between DateSerial((Year(Date()),(Month(Date())-1),21)) And DateSerial(Year(Date()),Month(Date()),20))
AND B.expdate Between DateSerial((Year(Date()),(Month(Date())-1),21) And DateSerial(Year(Date()),Month(Date()),20));
please help me
Use a sub-select to locate the minimum date, then join to the to get the row matching that date.
SELECT
a.`Purdate` AS a.`Date1`, a.`Qty`, a.`Rate`
FROM `TableName` a
JOIN (SELECT MIN(`PurDate`) as `minDate`
FROM `TableName`
WHERE `Icode` = '1') b
ON b.`minDate` = a.`PurDate`
WHERE a.`Icode` = '1'
Since you don't need grouping you can just order by the date column and get the first two rows.
SELECT PurDate, Qty, Rate FROM TableName WHERE Icode = '1' ORDER BY PurDate LIMIT 2
use corelated sub query and union
select A.* from
(
select * from tablename t1 #1st min date will return
where t1.purdate in
(select min(purdate) from
tablename t2 where t2.icode=t1.icode
)
union
select t1.* from tablename t1 inner join
(SELECT
Icode
, Purdate
FROM (
SELECT
#row_num :=IF(#prev_value=Icode,#row_num+1,1) AS rn
, mp.Icode
, mp.Purdate
, #prev_value := Icode
FROM tablename mp
CROSS JOIN (SELECT #row_num :=1, #prev_value :='') vars
ORDER BY
mp.Icode
, mp.Purdate DESC
) d
WHERE rn = 2
) t2
on t1.Icode=t2.Icode and t1.Purdate=t2.Purdate
) as A where A.Icode in (......)
In MySql I need to select top student in every class in a school in termid=10 to get discount for next term enrollment .
Please notice that total is not in table(I put in below for clearing problem)
I have this workbook table for all students workbook:
id studentid classid exam1 exam2 total termid
1 2 11 20 40 60 10
2 1 22 40 20 60 10
3 4 11 40 20 60 10
4 5 33 10 60 70 10
5 7 22 10 40 50 10
6 8 11 10 30 40 10
7 9 33 20 45 65 10
8 11 11 null null null 10
9 12 54 null null null 02
10 13 58 null null null 02
1st challenge is : exam1 and exam2 are VARCHAR and total is not in table (as i explained).
2nd challenge is : as you can see in id=8 std #11 has not numbers
3rd challenge is : may be two students have top level so they must be in result.
I need result as :
id studentid classid exam1 exam2 total termid
1 2 11 20 40 60 10
3 4 11 40 20 60 10
4 5 33 10 60 70 10
2 1 22 40 20 60 10
i have this query but not work good as i mention.
SELECT DISTINCT id,studentid,classid,exam1,exam2,total,termid ,(CAST(exam1 AS DECIMAL(9,2))+CAST(exam2 AS DECIMAL(9,2))) FROM workbook WHERE ClassId = '10';
You can get the total for the students by just adding the values (MySQL will convert the values to numbers). The following gets the max total for each class:
select w.classid, max(coalesce(w.exam1, 0) + coalesce(w.exam2, 0)) as maxtotal
from workbook w
group by w.classid;
You can then join this back to the original data to get information about the best students:
select w.*, coalesce(w.exam1, 0) + coalesce(w.exam2, 0) as total
from workbook w join
(select w.classid, max(coalesce(w.exam1, 0) + coalesce(w.exam2, 0)) as maxtotal
from workbook w
group by w.classid
) ww
on w.classid = ww.classid and (coalesce(w.exam1, 0) + coalesce(w.exam2, 0)) = ww.maxtotal;
Another approach is to join the table with itself. You find out the max for each class and then join all students of this class which match the class max:
max for each class (included in the final statement already):
SELECT classid, MAX(CAST(exam1 AS UNSIGNED) + CAST(exam2 AS UNSIGNED)) as 'maxtotal'
FROM students
WHERE NOT ISNULL(exam1)
AND NOT ISNULL(exam2)
GROUP BY classid
The complete statement:
SELECT s2.*, s1.maxtotal
FROM (SELECT classid, MAX(CAST(exam1 AS UNSIGNED) + CAST(exam2 AS UNSIGNED)) as 'maxtotal'
FROM students
WHERE NOT ISNULL(exam1)
AND NOT ISNULL(exam2)
GROUP BY classid) s1
JOIN students s2 ON s1.classid = s2.classid
WHERE s1.maxtotal = (CAST(s2.exam1 AS UNSIGNED) + CAST(s2.exam2 AS UNSIGNED));
SQL Fiddle: http://sqlfiddle.com/#!2/9f117/1
Use a simple Group by Statement:
SELECT
studentid,
classid,
max(coalesce(exam1,0)) as max_exam_1,
max(coalesce(exam2,0)) as max_exam_2,
sum(coalesce(exam1,0) + coalesce(exam2,0)) as sum_exam_total,
termid
FROM
workbook
WHERE
termid=10
GROUP BY
1,2
ORDER BY
5
Try something like this:
SELECT id,studentid,classid,exam1,exam2,(CAST(exam1 AS DECIMAL(9,2))+CAST(exam2 AS DECIMAL(9,2))) AS total,termid FROM `workbook` WHERE ((CAST(exam1 AS DECIMAL(9,2))+CAST(exam2 AS DECIMAL(9,2)))) > 50
Thanks all my friends
I think combine between 2 answer in above is best :
SELECT s2.*, s1.maxtotal
FROM (SELECT ClassId, MAX(
coalesce(exam1,0)+
coalesce(exam2,0)
) as 'maxtotal'
FROM workbook
WHERE
(
termid = '11'
)
GROUP BY ClassId) s1
JOIN workbook s2 ON s1.ClassId = s2.ClassId
WHERE s1.maxtotal = (
coalesce(exam1,0)+
coalesce(exam2,0)
) AND (s1.maxtotal >'75');
last line is good for s1.maxtotal=0 (some times student scores have not be entered and all equals 0 so all will shown as best students) or some times we need minimum score (to enroll in next term).
So thanks all
I am developing an SSRS report with the following dataset (Table-1). I am grouping by Account and Period. My goal is to get the Total Expense and the Budget within a group. Because the Budget data is duplicated per group, I cannot use SUM() function for Budget. How do I remove the duplicates so the new dataset looks like this? (Table-2) Please advice. Thank you for your time.
Table-1
ID Account Period Expense Budget
1 100 201301 20 100
2 100 201301 30 100
3 100 201302 10 150
4 100 201302 40 150
5 200 ...................
Table-2
ID Account Period Expense Budget
1 100 201301 20 100
2 100 201301 30 NULL
3 100 201302 10 150
4 100 201302 40 NULL
5 200 ...................
If you really want to make duplicate budgets null try this update command
please check sqlfiddle http://sqlfiddle.com/#!3/1e619/11
Update table1
set budget = null
where id in
(
select aa.id from
(
select id,row_number()
over(partition by Budget order by Period) as rno
from table1
) aa
where rno > 1
);
select * from table1;
good luck.
I would use a windowed function if you have to do that grouping in SQL. If you can do it in SSRS just add a 'Row Grouping Parent' it would be better.
For SQL I would do this:
declare #Temp table ( ID int identity, Account int, period int, expense int, budget int);
insert into #Temp values (100, 201301, 20, 100),(100, 201301, 30, 100),(100, 201302, 10, 150),(100, 201302, 40, 150)
select *
from #Temp
select
ID
, Account
, Period
, Expense
, case when (row_number() over(partition by Budget order by Period) = 1) then Budget end as Budget-- only shows first occurrence of an order amount ordering by person
from #Temp