Is there a way to sum rows only when they meet certain condition?, If they dont they must be copied to the new table. For example, if i have this table
| id | A | B |
--------------
| 1 | a | 2 |
| 1 | b | 4 |
| 1 | c | 1 |
| 2 | a | 4 |
| 3 | a | 1 |
| 3 | b | 5 |
I want an output like this
| id | A | B |
--------------
| 1 | a,b | 6 |
| 1 | c | 1 |
| 2 | a | 4 |
| 3 | a,b | 6 |
It will only sum if column 'A' is 'a' or 'b', it will just copy the value if its 'c'
You can do this in two different Select queries. In first Select query, just consider the cases where A has either values 'a' or 'b'. In the second Select query, consider the rest of the values (A NOT IN ('a','b'))
Use UNION ALL to combine the results into a Derived Table.
Order the Derived table result-set in ascending order by id.
We use aggregation functions like Group_concat() and Sum() to get comma separated string (for a and b), and sum of the B values, respectively.
Try the following:
SELECT dt.*
FROM
(
SELECT id,
GROUP_CONCAT(DISTINCT A) AS A,
SUM(B) AS B
FROM your_table
WHERE A IN ('a','b')
GROUP BY id
UNION ALL
SELECT id,
A,
B
FROM your_table
WHERE A NOT IN ('a', 'b')
GROUP BY id, A, B
) AS dt
ORDER BY dt.id ASC
Your example does not show all possible cases.
But I think that probably you don't need to overcomplicate solution with UNION
http://sqlfiddle.com/#!9/d473d3/6
SELECT id,
GROUP_CONCAT(A),
SUM(B)
FROM abc
GROUP BY CONCAT(id, IF(A IN ('a','b'),'$',A))
Related
I have a table that has an autoincremented numeric primary. I'm trying to get a count of rows that match a condition grouped by increments of their primary key. Given the data:
| id | value |
|----|-------|
| 1 | a |
| 2 | b |
| 3 | a |
| 4 | a |
| 5 | b |
| 6 | a |
| 7 | b |
| 8 | a |
| 9 | b |
| 10 | b |
| 11 | a |
| 12 | b |
If I wanted to know how many rows matched value = 'a' for every five rows, the result should be:
| count(0) |
|----------|
| 3 |
| 2 |
| 1 |
I can nest a series of subqueries in the SELECT statement, like such:
SELECT (SELECT count(0)
FROM table
WHERE value = 'a'
AND id > 0
AND id <= 5) AS `1-5`,
(SELECT count(0)
FROM table
WHERE value = 'a'
AND id > 5
AND id <=10) AS `6-10`,
...
But is there a way to do this with a GROUP BY statement or something similar where I don't have to manually write out the increments? If not, is there a more time efficient method than a series of subqueries in the SELECT statement as in the above example?
You could divide the ID by 5 and then ceil the result:
SELECT CONCAT((CEIL(id / 5.0) - 1) * 5, '-', CEIL(id / 5.0) * 5), COUNT(*)
FROM mytable
WHERE value = 'a'
GROUP BY CEIL(id / 5.0)
The following aggregated query should do the trick :
SELECT CEIL(id/5), COUNT(*)
FROM table
WHERE value = 'a'
GROUP BY CEIL(id/5)
I need to get AVG for every row in SQL for example:
this is the first table
+ ---+------+-------------+
| course_id | course_name |
+ ----------+-------------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | g |
+ ---+------+-------------+
This is the second table
I need to get AVG for both id 1 and 2. the result for example:
+ -------------------+------+----------+
| course_feedback_id | rate |course_id |
+ -================--+------+----------+
| 1 | 4 | 1 |
| 2 | 3 | 1 |
| 3 | 2 | 2 |
+ -------------------+------+----------+
this is the final answer that i need
+ ----------------------+
| course_id | AVG(rate) |
+ -=======--+-----------+
| 1 | 3.5 |
| 2 | 2 |
+ ----------------------+
I tried this soulution but it will give me only the first row not all records.
SELECT *, AVG(`rate`) from secondTable
please help
SELECT `id`, AVG(`rate`) FROM `your_table` GROUP BY `id`
Try this:
SELECT c.course_id, AVG(fb.rate)
FROM course AS c
INNER JOIN course_feedback AS fb ON fb.course_id = c.course_id
GROUP BY c.course_id
Select course_id,t2.rate from table1 where course_id,rate in (Select course_id,avg(rate) as rate from table group by course_id t2)
When you have multiple entries/redundant entries and you want to find some aggregation per each as in this case you got id containing redundant records, In such cases always try to use group by as group by as the name says will group records of the column to which it is applied and if you apply aggregation avg in this case will be groupwise column to which it is being applied not as a whole like for id 1 we have 2 redundant entries so itll apply avg(id1_entries)..likewise as a group.
Is there a way to limit a query in discrete groups? For example, let's say I have this query below.
| col1 | col2 |
---------------
| 1 | A |
| 1 | B |
| 2 | C |
| 2 | D |
| 3 | E |
| 3 | F |
I want the limit on this query to be 5 rows. However, I only want it to show discrete complete groups based on the first column. So that means I don't want to show (3, E) since (3, F) would be cut off. So it would only show the first 4 rows.
Is there a way to write this dynamic logic into a MySQL query?
Count rows in a subquery:
select col1, col2
from mytable m1
where (select count(*) from mytable m2 where m2.col1 <= m1.col1) <= 5
order by col1, col2;
I need to find the row with maximum count. There's only one table, so it should be easy, but it isn't.
Below is the content of table:
+------+------+------+
| row1 | row2 | row3 |
+------+------+------+
| 3 | 2 | 1 |
| 6 | 4 | 5 |
| 6 | 2 | 1 |
+------+------+------+
I need to find maximum count item for row1:
Using:
SELECT COUNT(*) AS c, row1 AS name
FROM draw
GROUP BY name;
Give me the result:
+------+------+
| c | name |
+------+------+
| 1 | 3 |
| 2 | 6 |
+------+------+
But I want to display only one row with the maximum "c":
+------+------+
| c | name |
+------+------+
| 2 | 6 |
+------+------+
Using:
SELECT MAX(c), name (
SELECT COUNT(*) AS c, row1 AS name
FROM draw GROUP BY name
) AS counts;
Give me result:
+------+------+
| c | name |
+------+------+
| 2 | 3 |
+------+------+
It means that it gives maximum count (c), but give first number in name row.
Is there way to fix it?
I think this is what you want, but your requirements are a little unclear. If this was any other platform you could use windowing functions would would be better.
SELECT *
FROM (
SELECT COUNT(*) AS c, row1
FROM draw
GROUP BY row1
) as Sub1
WHERE Sub.c = (
SELECT Max(c)
FROM (
SELECT COUNT(*) AS c
FROM draw
GROUP BY row1
) as Sub2
) as Sub3
select top 1 row1, count(*)
from draw
group by row1
order by count(*) desc
Order by the count descending (i.e. highest count first) and take the first one only.
You can try this
SELECT COUNT( `row1` ) AS c, `row1`
FROM `draw`
GROUP BY `row1`
ORDER BY `row1` DESC
LIMIT 1
This seems to be a convoluted problem, but I'll try my best to articulate the idea and illustrate a scenario. Essentially I have two tables that need to be combined and returned as the result set for a single query. One table needs to be merged into the other in a specific order.
Say table one is called Articles and table two is called Features. Both tables have an ID field with unique numbers. Articles has a date field which will be used to initially sort its records in descending order. The Features table has a Delta field which be used initially to sort its records. Some of the records in the Features table are placeholders and are not meant to be included in the final set. Their only purpose is to affect the sort order. Each record has a unique value in the Delta field, from 1 - X which will be used to sort these records. Another field called Skip has a value of 1 if it should be eliminated when merging the two tables together. Again, the only purpose to the skipped records is to take up space during the initial sort on the Features table. Even though they are unnecessary, they exist and can't be deleted.
The tricky part is that when the results from both tables are merged, any non-skipped records from the Features table need to be inserted into the results from the Articles table in the exact order they appears in the Features table.
So lets say I have 6 records in the Features table, A - F and the order field ranges from 1 - 6. Records A,B,D,E all have a value of 1 in the Skip field. That means I'm only interested in records C and F both of which need to be inserted into the final record set in positions 3 and 6 respectively.
The records may look something like this for the Articles table:
+----+------------+
| id | date |
+----+------------+
| 1 | 9999999999 |
+----+------------+
| 2 | 9999999998 |
+----+------------+
| 3 | 9999999997 |
+----+------------+
| 4 | 9999999996 |
+----+------------+
| 5 | 9999999995 |
+----+------------+
| 6 | 9999999994 |
+----+------------+
| 7 | 9999999993 |
+----+------------+
| 8 | 9999999992 |
+----+------------+
| 9 | 9999999991 |
+----+------------+
| 10 | 9999999990 |
+----+------------+
The Features table may look something like this:
+----+------+-------+------+
| id | name | delta | skip |
+----+------+-------+------+
| 11 | A | 1 | 1 |
+----+------+-------+------+
| 12 | B | 2 | 1 |
+----+------+-------+------+
| 13 | C | 3 | 0 |
+----+------+-------+------+
| 14 | D | 4 | 1 |
+----+------+-------+------+
| 15 | E | 5 | 1 |
+----+------+-------+------+
| 16 | F | 6 | 0 |
+----+------+-------+------+
The results would look something like this (not including any additional fields that might be needed to achieve my goal):
+----+
| id |
+----+
| 1 |
+----+
| 2 |
+----+
| 13 | (record from the Features table in the third position)
+----+
| 3 |
+----+
| 4 |
+----+
| 16 | (record from the Features table in the sixth position)
+----+
| 5 |
+----+
| 6 |
+----+
| 7 |
+----+
| 8 |
+----+
| 9 |
+----+
| 10 |
+----+
Hope my explanation makes sense. Any ideas?
Thanks,
Howie
I assume that there is a mistake in your example - record id=16 is sixth row in Features table, so should be after id=5 in results, not before.
Try the blelow query. Here is SQLFiddle.
select id from (
select `date`, null delta, id
from Articles
union all
select a.`date`, f.delta, f.id
from (
select (#x:=#x+1) rn, a.*
from Articles a, (select #x:=0) z
order by a.`date` desc
) a
join (
select (#y:=#y+1) rn, f.id, f.delta, f.skip
from Features f, (select #y:=0) z
order by f.delta
) f
on a.rn = f.rn
where f.skip <> 1
order by `date` desc, isnull( delta ), delta
) merge
Looks like this example in SQL Fiddle did it for me.
SELECT id, sort_order FROM (
SELECT `date`, NULL delta, id, (#a_count:=#a_count+1) sort_order
FROM Articles a_main, (SELECT #a_count:=-1) z
UNION ALL
SELECT a.`date`, f.delta, f.id, f.weighted_rn
FROM (
SELECT (#x:=#x+1) rn, a.*
FROM Articles a, (SELECT #x:=-1) z
ORDER BY a.`date` DESC
) a
JOIN (
SELECT (#y:=#y+1) rn, TRUNCATE((f.delta - #y - (1/#y)),2) AS weighted_rn, f.id, f.delta, f.skip
FROM Features f, (SELECT #y:=-1) z
WHERE f.skip <> 1
ORDER BY f.delta
) f
ON a.rn = f.rn
ORDER BY sort_order
) merge
Thanks to Kordirko for the framework.