The table has the values like,
group_name group_id parent_group_id amount
One 69 10 1000
Two 70 11 500
Three 71 69 700
Here I need to make sum of the values in amount column if the group id = 69 matches with the parent_group_id = 69 for which I have tried with
SUM(CASE WHEN fee_groups.groups_id = fee_groups.parent_fee_groups_id
THEN amount
ELSE 0
END) AS total
But above line doing nothing for me. If I am wrong with it then kindly help me to achieve the following result,
group_name group_id parent_group_id amount
One 69 10 1700
Two 70 11 500
Here the group_id and parent_group_id make a relationship, if there is a match from any of the parent_group_id with group_id then both are comes under single group and hence I need to sum both the values.
It doesn't make sense to me to include group_id and parent_group_id given what you want to do. You also don't explain what happens to the "71".
select min(group_name) as group_name,
sum(amount)
from t
group by (case when 69 not in (group_id, parent_group_id) then group_name end);
This will combine the groups that share "69" and keep the others separate.
Try this solution:
SELECT t1.group_name, t1.group_id, t1.parent_group_id,
(t1.amount + IFNULL(t2.amount,0)) Amount
FROM Table1 t1
LEFT JOIN Table1 t2
ON t1.group_id = t2.parent_group_id
OR t2.group_id = t1.parent_group_id
WHERE t1.group_name < t2.group_name OR t2.group_name IS NULL
GROUP BY t1.group_name, t1.group_id, t1.parent_group_id
OUTPUT:
group_name group_id parent_group_id Amount
One 69 10 1700
Two 70 11 500
Try this
SELECT
group_name,group_id,parent_group_id,
(CASE WHEN group_id = 69 THEN
(amount+(SELECT amount FROM table1 WHERE parent_group_id = 69))
ELSE amount END) as new_amount
FROM Table1 WHERE parent_group_id !=69;
do the execute below query or this link
sqlfiddle
select t.group_name,t.group_id,t.parent_group_id,
(case when t.group_id = t1.parent_group_id then t1.amount + t.amount else t.amount end)
from t
left join t as t1 on t.group_id = t1.parent_group_id
where t.group_id <>71
Related
I have table with some customer invoices. I need return some record that SUM(price) less than 200 dollar, this mean return record until total or sum invoice price < 200$.
Sometimes i want return latest record back and sometimes from beginning.
I use MYSQL database and php.
table
-----------------------
id | customerId | price
1 20 15
2 15 10
3 65 42
4 44 12
5 23 78
6 11 66
7 16 95
8 33 48
I would recommend variables for calculating the cumulative sum:
select t.*
from (select t.*, (#s := #s + price) as sum_price
from t cross join
(select #s := 0) params
order by id
) t
where sum_price < 200;
let HAVING filter your results to those < 200:
SELECT SUM(price) as total, customerId
FROM table
GROUP BY customerId
HAVING total < 200
Edit
So you do not need the customer, but all the records for him: then use query above as a subquery:
SELECT maintable.Id, maintable.customerId, maintable.price
FROM table AS maintable
JOIN (
SELECT customerId
FROM table
GROUP BY customerId
HAVING SUM(price) < 200
) subq ON subq.customerId = maintable.customerId
SELECT
t.id,
t.customerid,
t.price,
(SELECT
sum(price) FROM Table1
WHERE Id <= t.id) 'CalculatedTotal'
FROM Table t
HAVING CalculatedTotal <=200
this query calculates and return rows having total less than 200.
I am trying to retrieve the minimum price of some models.
Each model belongs to a certain group which belongs to a product.
I have the following tables:
Product
model_id product_id price
1 1 100
2 1 120
3 1 100
4 1 200
5 1 250
10 1 20
11 1 50
12 1 50
Product Overview
model_id product_id group_id
1 1 A
2 1 A
3 1 A
4 1 A
5 1 A
10 1 B
11 1 B
12 1 B
Product Group Optional
group_id product_id
B 1
Some groups could be optional, which means price will be zero unless the member wants to choose otherwise.
So in the example above, I want to get the sum of minimum price from each group.
We have two groups, group A and group B.
Group A minimum price value is 100 (model_id 1 and 3)
Group B minimum price value is 20 (model_id 10) but because Group B is optional then that means minimum price value is 0.
Overall sum of min values: 100 (Group A) + 0 (Group B) = 100
My code so far:
SELECT po.group_id,
CASE WHEN
((SELECT COUNT(*) FROM product_group_optional pgo
WHERE po.group_id = group_id AND po.product_id = 1 AND po.product_id = product_id) >= 1)
THEN SUM(0)
ELSE SUM(p.price)
END AS sum_price
FROM product_overview po, product p
WHERE po.product_id = 1
AND po.model_id = p.model_id
AND p.price = (
SELECT MIN(p2.price)
FROM product p2, product_overview po2
WHERE po2.product_id = 1 AND po2.group_id = po.group_id
AND po2.model_id = p2.model_id
)
GROUP BY po.group_id
The output:
group_id sum_price
A 200
B 0
The problem is that I get 200 for Group A but it should be 100.
There are 2 models with min value 100, model 1 and 3. And I assume these are sum together = 100 + 100 = 200.
Issue a) But I want to just take the min value, no matter how many times this value exists.
Issue b) Also, I am trying to get the SUM of those two output SUM of Group A and Group B.
But I am not sure how to do it.
I want it to be done in this query.
Desired output
Sum of all groups
100
Can anyone lead me to the right direction please?
You can use the following query:
SELECT SUM(min_price)
FROM (
SELECT po.group_id,
MIN(CASE WHEN pgo.group_id IS NULL THEN price ELSE 0 END) AS min_price
FROM Product AS p
INNER JOIN Product_overview AS po
ON p.product_id = po.product_id AND p.model_id = po.model_id
LEFT JOIN Product_group_optional AS pgo ON po.group_id = pgo.group_id
GROUP BY po.group_id) AS t
I'm not sure that I understand the keys of your tables, and the problem as well.
There is few questions.
a) The answer should be 120?
b) If the Product has no price, the is price null?
c) If there is a Product in a group with null price and others with price, should it be counted as 0?
Here is how you could get the sum of the lower prices of each group, ignoring the product_group_optional for while:
SELECT t2.group_id, sum(t2.new_price)
FROM
(
SELECT t.group_id, t.new_price
FROM
(
SELECT po.group_id, if(ifnull(pgo.product_id, true), p.price, 0) as new_price
FROM product p, product_overview po
LEFT JOIN product_group_optional pgo ON po.group_id = pgo.group_id
WHERE p.model_id = po.model_id
ORDER by po.group_id, new_price
) t
GROUP BY t.group_id
) t2
The following mySQL query gets data from 2 tables, alerts_data and alerts_list. The first table has the data of an alert, and the second has the description of the alert. So in the alerts_data there are multiple rows with the same alerts_data_id that is the same with the alerts_id of alerts_list.
What i want to achieve, is to display something like this
alert number 51, 5 clicked , 2 closed
alert number 57, 13 clicked, 3 closed, 8 waiting
using mySQL or PHP (i do not know if i can get this through plain mySQL)
So for now with my knowledge I can not display the data of alert 51 in one row, but because of the different alerts_data_status i have to show 3 rows for each.
How can I do it as above?
SELECT COUNT( alerts_data_id ) AS total, alerts_data_id, alerts_data_status, alerts_list.alerts_title
FROM alerts_data
JOIN alerts_list ON
alerts_data.alerts_data_id = alerts_list.alerts_id
GROUP BY alerts_data_id, alerts_data_status
//output
total - alerts_data_id - alerts_data_status - alerts_title
5 - 51 - clicked - alert number 51
2 - 52 - closed - alert number 51
13 - 57 - clicked - alert number 57
3 - 57 - waiting - alert number 57
8 - 57 waiting - alert number 57
Note: the alerts number are just examples, it can be any number
// alert_data
id - alerts_data_id - alerts_data_status
// alerts_list
alerts_id - alerts_name - alerts_text
Here's a sqlfiddle: http://sqlfiddle.com/#!9/c70c2/1
This may be an application for GROUP_CONCAT().
You first want a summary of your alerts by alerts_data_id and alerts_data_status. This is a little complex, because your sqlfiddle has a whole bunch of empty alerts_data_status strings. Here, I'm replacing those empty strings with `?'. (http://sqlfiddle.com/#!9/c70c2/23/0)
SELECT COUNT(*) AS alerts_count,
alerts_data_id,
CASE WHEN LENGTH(alerts_data_status) = 0 THEN '?'
ELSE alerts_data_status END AS alerts_data_status
FROM alerts_data
GROUP BY alerts_data_id, alerts_data_status
You then want to roll that up inside another query
SELECT SUM(a.alerts_count) total,
a.alerts_data_id, b. alerts_name,
GROUP_CONCAT( CONCAT(a.alerts_count, ': ', a.alerts_data_status)
ORDER BY a.alerts_data_status
SEPARATOR "; " ) detail
FROM (
SELECT COUNT(*) AS alerts_count,
alerts_data_id,
CASE WHEN LENGTH(alerts_data_status) = 0 THEN '?'
ELSE alerts_data_status END AS alerts_data_status
FROM alerts_data
GROUP BY alerts_data_id, alerts_data_status
) a
JOIN alerts_list b ON a.alerts_data_id = b.alerts_id
GROUP BY a.alerts_data_id, b.alerts_name
This will give you one row for each distinct alerts_data_id. Each alert is identified by its count, its id, and its name. (http://sqlfiddle.com/#!9/c70c2/26/0)
Then the row will contain a semicolon-separated list of the counts of the different alert status.
If i understand you well i think here is what you need;
SELECT
COUNT( alerts_data.id ) AS total,
ad.id,
(SELECT count(*) from alert_list al where al.alerts_id=ad.id and alerts_data_status='clicked') as clicked,
(SELECT count(*) from alert_list al where al.alerts_id=ad.id and alerts_data_status='closed') as closed,
(SELECT count(*) from alert_list al where al.alerts_id=ad.id and alerts_data_status='waiting') as waiting,
FROM alerts_data ad
GROUP BY ad.id
Was checking other answers and your SQLFIDDLE and thought this might be a nicer approach:
SELECT alerts_list.alerts_title,
SUM(CASE WHEN alerts_data_status = 'clicked' THEN 1 ELSE 0 END) AS clicked,
SUM(CASE WHEN alerts_data_status = 'closed' THEN 1 ELSE 0 END) AS closed,
SUM(CASE WHEN alerts_data_status = 'waiting' THEN 1 ELSE 0 END) AS waiting
FROM alerts_data
JOIN alerts_list ON alerts_data.alerts_data_id = alerts_list.alerts_id
GROUP BY alerts_list.alerts_title
I have four tables
1.student-it contains id name etc
2.marks - it contains markid,student_id,batch,class,section,subject_id,exam_id,obt_mark
3.subject table - it contains sub_id,sub_name
4. exam_type- examtype_id, exam_name
i need mark ledger for batch-2014,class=5,section=1,exam_id=3 as shown below-
NAME ROLL NO SUB1 SUB2 SUB3 TOTAL RESULT POSITION RANK
RAM 0054 65 54 64 183 PASS FIRST 2
HAri 0054 65 54 65 184 PASS FIRST 1
gopal 0054 65 50 65 180 PASS FIRST 3
saroj 0054 65 44 65 174 PASS FIRST 4
Thanks in advance .
Here i have sql query
SELECT `marklists`.`mrk_sub_id1`, `marklists`.`mrk_marks`, `marklists`.`mrk_practical`,
`marklists`.`mrk_exam_type`, `students`.`id` as st_id, `students`.`st_roll`,
`students`.`st_name`, `students`.`batch`, `students`.`st_class`,
`students`.`st_section`, `courses`.`id`, `classes`.`class_name` as class_name,
`courses`.`sb_name` as subject_name, `courses`.`sb_fullmark` as full_marks,
`courses`.`sb_passmark` as pass_marks FROM (`marklists`)
LEFT JOIN `classes` ON `marklists`.`mrk_class` = `classes`.`id`
LEFT JOIN `students` ON `marklists`.`mrk_student_id`=`students`.`id`
LEFT JOIN `courses` ON `marklists`.`mrk_sub_id`=`courses`.`id`
WHERE `marklists`.`mrk_exam_type` = '3' AND `marklists`.`mrk_batch` = '3'
AND `marklists`.`mrk_class` = '1' AND `marklists`.`mrk_section` = '1'
and I need ledger like above any help??
Join the tables based on common key and for the titles which you need as subject you can use pivot operator to convert rows to column and use where clause for rest of the conditions
hope this helps.
Structure of my table : ID(int) | NUMBER(int) | CREATED_AT(date)
If I have three numbers : 10, 11 and 9, Can I get all rows from my table with same ratio of NUMBER values with decreasing consecutive CREATED_AT dates?
Examples :
If my numbers are : 10,11,9 ... The rows may be :
NUMBER | CREATED_AT
50 | 2012-03-18
51 | 2012-03-17
49 | 2012-03-16
Result must be "50"
If my numbers are : 50,40,60 ... The rows may be :
NUMBER | CREATED_AT
100 | 2012-02-20
90 | 2012-02-19
110 | 2012-02-18
Result must be "100"
...
I wasted a half of day for this, but I still have no Idea where to start...
P.S : I have about 5 000 rows in my table.
UPDATE
I did it with a bit of php code and a lot of mysql queries. Script execution time : ~6 seconds. [Tested on godaddy deluxe hosting] =)
I haven't tested it myself, but you can try this:
SELECT a.*,b.*,c.*
FROM table_name a
INNER JOIN table_name b
ON b.NUMBER = a.NUMBER + $range1 and DATEDIFF(b.CREATED_AT, a.CREATED_AT) = 1
INNER JOIN table_name c
ON c.NUMBER = b.NUMBER + $range2 and DATEDIFF(c.CREATED_AT, b.CREATED_AT) = 1
$range1, $range2 are variables number1 - number2 and number2 - number3.
In your example you have 10, 11 and 9. So, if t1.number = 10, then t2.number = t1.number + 1 and t3.number = t2.number - 2. This can be written into a query in this form -
SELECT t1.NUMBER
FROM (SELECT 50 AS `first`, 40 AS `second`, 60 AS `third`) AS seq
INNER JOIN `table` t1
ON `seq`.`first` <> t1.NUMBER
INNER JOIN `table` t2
ON `seq`.`second` <> t2.NUMBER
AND t1.CREATED_AT - INTERVAL 1 DAY = t2.CREATED_AT
AND CAST(t1.NUMBER AS SIGNED) - CAST(t2.NUMBER AS SIGNED) = `seq`.`first` - `seq`.`second`
INNER JOIN `table` t3
ON `seq`.`third` <> t3.NUMBER
AND t2.CREATED_AT - INTERVAL 1 DAY = t3.CREATED_AT
AND CAST(t2.NUMBER AS SIGNED) - CAST(t3.NUMBER AS SIGNED) = `seq`.`second` - `seq`.`third`;
EDIT - added the CAST to deal with negatives
This is not very efficient due to the join criteria but given such a small dataset it should be fine.