I'm trying to write a select statement in MySQL to get 5 rows after I get my match then sum how many times those numbers were repeated.
Example:
Raw Table
id
number
1
1
2
0
3
9
4
14
5
11
6
0
7
3
8
4
9
10
10
9
11
0
12
5
13
3
14
11
15
0
I need to find every row with the number 0, then after that select and show 5 rows after and counting the appearance of the numbers.
How can I select the numbers and get the count as a result?
The result of the first select should be like this:
id
number
3
9
4
14
5
11
6
0
7
3
7
3
8
4
9
10
10
9
11
0
12
5
13
3
14
11
15
0
The result of the count for every number in the last query.
Number
Count
9
2
14
1
11
2
0
3
3
3
4
1
10
1
5
1
This is a demo to get expected results:
Select numbers:
SELECT id, number
FROM (
SELECT b.id, b.number, ROW_NUMBER() OVER(PARTITION BY a.id ORDER BY b.id ASC) r
FROM numbers a
JOIN numbers b ON a.id < b.id
WHERE a.number = 0
) t WHERE t.r <= 5
ORDER BY id
Count numbers:
WITH n AS (
SELECT id, number
FROM (
SELECT b.id, b.number, ROW_NUMBER() OVER(PARTITION BY a.id ORDER BY b.id ASC) r
FROM numbers a
JOIN numbers b ON a.id < b.id
WHERE a.number = 0
) t WHERE t.r <= 5
)
SELECT number, COUNT(*) counts
FROM n
GROUP BY number
Sample data:
CREATE TABLE numbers (
id INT PRIMARY KEY auto_increment,
number INT NOT NULL
);
INSERT INTO numbers ( number ) VALUES (1),(0),(9),(14),(11),(0),(3),(4),(10),(9),(0),(5),(3),(11),(0);
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=1fe71080cfb27680eb2a37b721e5de2d
Update for MySQL v5.7
SELECT n.*
FROM numbers n
JOIN (
SELECT a.id, SUBSTRING_INDEX(GROUP_CONCAT(b.id ORDER BY b.id SEPARATOR ','), ',', 5) selections
FROM numbers a
JOIN numbers b ON a.id < b.id
WHERE a.number = 0
GROUP BY a.id
) t ON FIND_IN_SET(n.id, t.selections)
ORDER BY n.id
SELECT n.number, COUNT(*) counts
FROM numbers n
JOIN (
SELECT a.id, SUBSTRING_INDEX(GROUP_CONCAT(b.id ORDER BY b.id SEPARATOR ','), ',', 5) selections
FROM numbers a
JOIN numbers b ON a.id < b.id
WHERE a.number = 0
GROUP BY a.id
) t ON FIND_IN_SET(n.id, t.selections)
GROUP BY n.number
ORDER BY n.number
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=3be09acab5cd696ec4b01585eb5c32ed
Related
I have this sample table with Id, Grades:
Id Grades
1 50
1 60
1 70
1 40
1 80
1 65
2 80
2 67
2 100
2 90
2 60
etc
What I would like to do here is step by step:
Group them like this:
Between Assigned
1-50 D
51-70 C
71-90 B
91-100 A
and if the count of these groups is >=2, then assign the specified value above for each group:
if count(1-50)>=2 then D
if count(51-70)>=2 then C
if count(71-90)>=2 then B
if count(91-100)>=2 then A
so the output will be A,B,C,D or "". grouped by Id.
Thank you.
Try this query:
SELECT a.id, COALESCE(MAX(CASE
WHEN a.rank='D' AND a.cnt>=2 THEN 'D'
WHEN a.rank='C' AND a.cnt>=2 THEN 'C'
WHEN a.rank='B' AND a.cnt>=2 THEN 'B'
WHEN a.rank='A' AND a.cnt>=2 THEN 'A'
ELSE NULL
END),'') AS `rank`
FROM (
SELECT t.id,r.`rank`,COUNT(*) AS cnt
FROM (
SELECT 1 AS low, 50 AS high, 'D' AS `rank`
UNION ALL
SELECT 51,70,'C'
UNION ALL
SELECT 71,90,'B'
UNION ALL
SELECT 91,100,'A') r
INNER JOIN t t
ON t.grades>=r.low
AND t.grades<=r.high
GROUP BY t.id,r.`rank`) a
GROUP BY a.id
I am looking to generate the results into the horizontal union. I could able to combine together and generate the results. However, I need to show the results in the expected results format.
SQL
(SELECT
kpa_id AS 'KPA', SUM(weightage) AS 'Total'
FROM
pmm_question_details
WHERE
weightage NOT LIKE '%-%'
GROUP BY kpa_id) UNION (SELECT
kpa_id AS 'KPA', SUM(weightage_value) AS 'Acheived'
FROM
pmm_answer_details
WHERE
application_id = 2
AND archive_value = 'No'
GROUP BY kpa_id)
Actual Results
1 14
2 37
3 19
4 40
5 51
6 24
1 12
2 19
3 0
6 2
Expected Results
1 14 1 12
2 37 2 19
3 19 3 0
4 40 6 2
5 51
6 24
If we can assume pmm_question_Details will always have as many or more records than pmm_answer_details... then two subqueries and a left join should do the trick with a join on a uservariable rownum (RN)
SELECT A.KPA, A.Total, B.KPA, B.Acheived
FROM (SELECT kpa_id AS 'KPA'
, SUM(weightage) AS 'Total'
, #RN1 := #RN1 + 1 as RN
FROM pmm_question_details
CROSS JOIN (SELECT #RN1 :=0) r1
WHERE weightage NOT LIKE '%-%'
ORDER BY KPA
GROUP BY kpa_id) A
LEFT JOIN (SELECT kpa_id AS 'KPA'
, SUM(weightage_value) AS 'Acheived'
, #RN1 := #RN2 + 1 as RN
FROM pmm_answer_details
CROSS JOIN (SELECT #RN2 :=0) r2
WHERE application_id = 2
AND archive_value = 'No'
ORDER BY KPA
GROUP BY kpa_id) B
on A.RN = B.RN
ORDER BY A.KPA
Though I must admit I don't see why a rownumber is needed if you could just left join on the KPA_ID in the first place...
if this could be the Expected results... (and again assuming pmm_question has all the IDs which could be in pmm_answer... )
Expected Results
1 14 1 12
2 37 2 19
3 19 3 0
4 40
5 51
6 24 6 2
Then the query would just be...
SELECT A.KPA, A.Total, B.KPA, B.Acheived
FROM (SELECT kpa_id AS 'KPA', SUM(weightage) AS 'Total'
FROM pmm_question_details
WHERE weightage NOT LIKE '%-%'
GROUP BY kpa_id) A
LEFT JOIN (SELECT kpa_id AS 'KPA', SUM(weightage_value) AS 'Acheived'
FROM pmm_answer_details
WHERE application_id = 2
AND archive_value = 'No'
GROUP BY kpa_id) B
on A.KPA = B.KPA
Have to show on specific count . Means i have to show max score value 4 times then less than that score to 3 times and so on
I have table like:-
ID Score
1 1
2 1
3 1
4 1
5 2
6 2
7 2
8 3
9 3
10 4
11 4
12 4
and I am expecting output like:-
Score
1
1
1
2
2
3
4
Try this:
SELECT Score
FROM
(SELECT a.Score, a.ID, count(*) as RN FROM TableName a
JOIN TableName b ON a.Score = b.Score AND a.ID >= b.ID
GROUP BY a.Score, a.ID) T
WHERE RN>1
Result:
SCORE
1
1
1
2
2
3
4
4
An example in SQL Fiddle.
Explanation:
In the inner query, we are selecting a row number partitioned by ID and order by score. And then we select Score from the inner query whose Row number is greater than 1 (inorder to omit 1 record).
SELECT x.*
FROM my_table x
JOIN my_table y
ON y.marks = x.marks
AND y.id <= x.id
GROUP
BY x.marks
, x.id
HAVING COUNT(0) <= MAX(4-x.marks)
ORDER
BY marks DESC,id;
The code i use gives me the correct information based on a date in a where clause. I want to have the same information on other dates. So now I have to change the date myself and run the code, copy/paste it somewhere else and start over again with a new date. That takes a lot of work if i want the information for every day of the year. Is it possible to automaticly change the date in the where clause and what is the best or easiest way to do that?
Select t4.Count, t4.Status
From(
SELECT count(l.VoerID) as Count, l.Datum, l.Status, l.LogID
FROM (
SELECT k.VoerID, k.Datum, MAX(k.LogID) AS LogID
FROM DB.LogStatus k
Where Datum < '2013-07-01'
GROUP BY k.VoerID
) m
JOIN DB.LogStatus l
ON l.VoerID = m.VoerID AND l.LogID = m.LogID
Where status in ('B','IN1','IN2''V','Reserv')
Group by Status
)t4
EDIT:
original table (selected on one VoerID) (table consist of thousands of VoerID's)
LogID Datum UserID Status Time VoerID
1299772 2013-04-17 259 N 14:09:11 50174
1319774 2013-05-23 68 B 11:19:17 50174
1320038 2013-05-23 197 IN1 16:53:30 50174
1322002 2013-05-28 68 IN2 09:22:32 50174
1325052 2013-05-31 161 G 09:00:59 50174
1325166 2013-05-31 10 400 09:15:12 50174
1325182 2013-05-31 10 V 09:30:07 50174
1325208 2013-05-31 10 V 09:45:06 50174
1325406 2013-05-31 10 Reserv 11:45:06 50174
1325522 2013-05-31 10 Reserv 12:15:06 50174
1325954 2013-05-31 10 Reserv 15:15:13 50174
1328474 2013-06-05 10 Reserv 13:15:06 50174
1329230 2013-06-06 10 Reserv 09:45:03 50174
1329244 2013-06-06 10 Archived 10:00:08 50174
1329268 2013-06-06 10 Archived 10:15:08 50174
1330286 2013-06-07 10 Archived 10:15:06 50174
I want to now what was the status of the VoerID on all first of months. so on 2013-05-01 status = N, on 2013-06-01 status = Reserv and from 2013-07-01 it is Archived.
So above is for one VoerID. I want to count the number of VoerID's per first of month, per last LOGID before the first of next month and per status
Finally if I get the information i want to edit it in MSExcel to a crosstable and Chart:
1-1-2013 1-2-2013 1-3-2013 1-4-2013 1-5-2013
N 20 22 24 26 28
B 23 21,5 20 18,5 17
IN1 12 15 18 21 24
IN2 15 7 14 18 25
V 800 1000 1200 1400 1600
Reserv 50 63 76 89 102
Archived 100000 101220 102440 103660 104880
Doing a cross join of all the days of the year, then grouping by that day.
Something like this:-
SELECT COUNT(l.VoerID) as COUNT, m.aDate, l.Status
FROM
(
SELECT Sub1.aDate, k.VoerID, MAX(k.LogID) AS LogID
FROM DB.LogStatus k
CROSS JOIN
(
SELECT DATE_ADD('2013-01-01', INTERVAL units.i + tens.i * 10 + hundreds.i * 100 DAY) AS aDate -- return the first day of the year + all the numbers from 0 to 999
FROM (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units -- Select units of days
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens -- select tens
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) hundreds -- select hundreds
WHERE DATE_ADD('2013-01-01', INTERVAL units.i + tens.i * 10 + hundreds.i * 100 DAY) <= '2013-12-31' -- limit the dates to the days of the specific year
) Sub1
WHERE k.Datum < Sub1.aDate -- This should give up multiple copies of record, one for each date where the d Datum is less that that date
GROUP BY Sub1.aDate, k.VoerID -- GRoup by date and id, so getting the max log id for each date and id
) m
JOIN DB.LogStatus l
ON l.VoerID = m.VoerID AND l.LogID = m.LogID -- Join where log it is the max log id
WHERE status in ('x','y','z')
GROUP BY m.aDate, Status
EDIT - or for each month:-
SELECT COUNT(l.VoerID) as COUNT, m.aDate, l.Status
FROM
(
SELECT Sub1.aDate, k.VoerID, MAX(k.LogID) AS LogID
FROM DB.LogStatus k
CROSS JOIN
(
SELECT DATE_ADD('2013-01-01', INTERVAL units.i MONTH) AS aDate -- return the first day of each month of the year
FROM (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION SELECT 11) units -- Select units of days
) Sub1
WHERE k.Datum < Sub1.aDate -- This should give up multiple copies of record, one for each date where the d Datum is less that that date
GROUP BY Sub1.aDate, k.VoerID -- GRoup by date and id, so getting the max log id for each date and id
) m
JOIN DB.LogStatus l
ON l.VoerID = m.VoerID AND l.LogID = m.LogID -- Join where log it is the max log id
WHERE status in ('x','y','z')
GROUP BY m.aDate, Status
Select count(*) as c from casting where ord = 1 Group by actorid Order by count(*) DESC
The result is
15 15 14 13 12 10 7 7 7 7 5 5
Then i would like to get the result only greater than 10 ??how to do that thanks~~
SELECT count(*) AS c
FROM casting
WHERE ord = 1
GROUP BY actorid
HAVING c > 10
ORDER BY c DESC
You can consider HAVING the WHERE clause for GROUP BY aggregates.
SELECT COUNT(*) AS c FROM casting WHERE ord = 1 GROUP BY actorid HAVING COUNT(*) > 10 ORDER BY COUNT(*) DESC
HAVING c > 10
Place this between group by and order by