Image we have a table like this:
table1
+----------+----------+--------+------------+
| position | epoc | name | value |
+----------+----------+--------+------------+
| 1 | 1 | A | v01 |
| 1 | 1 | B | v02 |
| 1 | 1 | C | v03 |
| 1 | 2 | A | v04 |
| 1 | 2 | B | v05 |
| 1 | 2 | C | v06 |
| 1 | 3 | A | v07 |
| 1 | 3 | B | v08 |
| 1 | 3 | C | v09 |
| 1 | 4 | A | v10 |
| 1 | 4 | B | v11 |
| 1 | 4 | C | v12 |
| 2 | 5 | A | v13 |
| 2 | 5 | B | v14 |
| 2 | 5 | C | v15 |
| 2 | 6 | A | v16 |
| 2 | 6 | B | v17 |
| 2 | 6 | C | v18 |
| 2 | 7 | A | v19 |
| 2 | 7 | B | v20 |
| 2 | 7 | C | v21 |
| 2 | 8 | A | v22 |
| 2 | 8 | B | v23 |
| 2 | 8 | C | v24 |
+----------+----------+--------+------------+
I want to be able to get this table:
table2
+----------+--------------------+
| position | value |
+----------+--------------------+
| 1 | v01,v02,v04,v05 |
| 2 | v13,v14,v16,v17 |
+----------+--------------------+
the conditions are:
JUST the "value" of rows with "name" A OR B;
JUST "epocs" that are the first 2 unique results in "position" (epoc 3,4,7,8 are discarded)
GROUP by table1 position (for each position I want the concat of the values that match previous conditions)
This might be what you are looking for:
select position,
group_concat(value order by overall_row_num) value
from
(
select position,
name,
value,
epoc,
#num := if(#position = `position`, #num + 1, 1) as group_row_number,
#position := `position` as dummy,
overall_row_num
from
(
select position, name,
epoc,
value,
#rn:=#rn+1 overall_row_num
from t1, (SELECT #rn:=0) r
where name in ('A', 'B')
order by position, epoc
) x
order by overall_row_num
) x1
where group_row_number <= 4
group by position
See SQL Fiddle with demo
Related
I have a table that cotains the id of the students, the course name and the course level.
+----+--------+-------+
| Id | Course | Level |
+----+--------+-------+
| 1 | A | 1 |
| 2 | A | 1 |
| 1 | B | 1 |
| 3 | B | 1 |
| 4 | C | 2 |
+----+--------+-------+
From this, I want to know the percentage each course covers by level.
Like in the below table:
+-------+--------+----------------+
| Level | Course | Count_by_level |
+-------+--------+----------------+
| 1 | A | 50% |
| 1 | A | 50% |
| 1 | B | 50% |
| 1 | B | 50% |
| 2 | C | 100% |
+-------+--------+----------------+
How can I do this using SQL?
SQL DEMO
SELECT S.[Id] , S.[Course], S.[Level], T.ctotal,
100.0 / T.ctotal
FROM students S
JOIN ( SELECT [Course], COUNT(*) as ctotal
FROM students
GROUP BY [Course]
) T
ON S.[Course] = T.[Course]
OUTPUT
| Id | Course | Level | ctotal | |
|----|--------|-------|--------|-----|
| 1 | A | 1 | 2 | 50 |
| 2 | A | 1 | 2 | 50 |
| 1 | B | 1 | 2 | 50 |
| 3 | B | 1 | 2 | 50 |
| 4 | C | 2 | 1 | 100 |
Just another option using the window functions (assuming 2012+)
Example
Select [Level]
,[Course]
,Pct = 100.0 / sum(1) over (partition by [Level],[Course])
From YourTable
Returns
Level Course Pct
1 A 50.000000
1 A 50.000000
1 B 50.000000
1 B 50.000000
2 C 100.000000
How to get count of combinations from database?
I have to database tables and want to get the count of combinations. Does anybody know how to put this in a database query, therefore I haven't a db request for each trip?
Trips
| ID | Driver | Date |
|----|--------|------------|
| 1 | A | 2015-12-15 |
| 2 | A | 2015-12-16 |
| 3 | B | 2015-12-17 |
| 4 | A | 2015-12-18 |
| 5 | A | 2015-12-19 |
Passengers
| ID | PassengerID | TripID |
|----|-------------|--------|
| 1 | B | 1 |
| 2 | C | 1 |
| 3 | D | 1 |
| 4 | B | 2 |
| 5 | D | 2 |
| 6 | A | 3 |
| 7 | B | 4 |
| 8 | D | 4 |
| 9 | B | 5 |
| 10 | C | 5 |
Expected result
| Driver | B-C-D | B-D | A | B-C |
|--------|-------|-----|---|-----|
| A | 1 | 2 | - | 1 |
| B | - | - | 1 | - |
Alternative
| Driver | Passengers | Count |
|--------|------------|-------|
| A | B-C-D | 1 |
| A | B-D | 2 |
| A | B-C | 1 |
| B | A | 1 |
Has anybody an idea?
Thanks a lot!
Try this:
SELECT Driver, Passengers, COUNT(*) AS `Count`
FROM (
SELECT t.ID, t.Driver,
GROUP_CONCAT(p.PassengerID
ORDER BY p.PassengerID
SEPARATOR '-') AS Passengers
FROM Trips AS t
INNER JOIN Passengers AS p ON t.ID = p.TripID
GROUP BY t.ID, t.Driver) AS t
GROUP BY Driver, Passengers
The above query will produce the alternative result set. The other result set can only be achieved using dynamic sql.
Demo here
This question already has answers here:
Using LIMIT within GROUP BY to get N results per group?
(14 answers)
Closed 7 years ago.
Just have a tricky blockING with MySQL.
I've 3 tables :
TV
| TV_ID | TV_name |
----------------------
| 1 | HBO |
| 2 | BBC |
| 3 | Fox news |
----------------------
----------------------
----------------------
Emission
| E_ID | E_TV_ID | E_NAME |
-------------------------------
| 1 | 1 | Weather |
| 2 | 1 | News |
| 3 | 1 | FAKE1 |
| 4 | 1 | FAKE2 |
| 5 | 1 | FAKE3 |
| 6 | 1 | FAKE4 |
| 7 | 2 | FAKE5 |
| 8 | 2 | FAKE6 |
| 9 | 2 | FAKE7 |
| 10 | 2 | FAKE8 |
| 11 | 2 | FAKE9 |
| 12 | 2 | FAKE10 |
| 13 | 2 | FAKE11 |
| 14 | 3 | FAKE12 |
| 15 | 3 | FAKE13 |
| 16 | 3 | FAKE14 |
| 17 | 3 | FAKE15 |
| 18 | 3 | FAKE16 |
| 19 | 3 | FAKE17 |
| 20 | 3 | FAKE18 |
-------------------------------
-------------------------------
-------------------------------
Replay
| R_ID | R_E_ID | R_DATE | R_URL_REPLAY |
-------------------------------------------
| 1 | 1 | 20150431 | URL1 |
| 2 | 20 | 20150431 | URL2 |
| 3 | 19 | 20150431 | URL3 |
| 4 | 2 | 20150431 | URL4 |
| 5 | 7 | 20150431 | URL5 |
| 6 | 16 | 20150430 | URL6 |
| 7 | 10 | 20150430 | URL7 |
| 8 | 1 | 20150430 | URL8 |
| 9 | 4 | 20150430 | URL9 |
| 10 | 9 | 20150430 | URL10 |
| 11 | 19 | 20150429 | URL11 |
| 12 | 2 | 20150429 | URL12 |
| 13 | 1 | 20150429 | URL13 |
| 14 | 12 | 20150429 | URL14 |
-------------------------------------------
-------------------------------------------
-------------------------------------------
And I want to create ONLY ONE query to get 3rd last emission of each TV, order by date and TV (if possible).
So for this exemple, I've 3 TV. 3*3 = 9 emissions, like :
| TV_ID | E_NAME | R_URL_REPLAY |
-------------------------------------
| 1 | Weather | URL1 |
| 1 | FAKE2 | URL4 |
| 1 | FAKE6 | URL8 |
| 2 | FAKE3 | URL5 |
| 2 | FAKE8 | URL7 |
| 2 | FAKE7 | URL10 |
| 3 | FAKE18 | URL2 |
| 3 | FAKE17 | URL3 |
| 3 | FAKE14 | URL6 |
I've try many solution (INNER JOIN -- SELECT .. FROM ( SELECT ...) -- Use var #:= -- Sub-sub-sub-sub query ) but not works..
Only works if I use UNION, but I've more than 20 TV, and write 20 UNION is really urgly..
If you have suggestion,
Thanks in advance,
It's not straightforward, but in a nutshell, sort your replays by tv and date, then rank them, then select those that match your rank criteria.
select *
from (
select if(#prev = e_tv_id, #rank := #rank +1, #rank := 1 and #prev := e_tv_id) as rank, q.*
from (
select e.e_tv_id, r_date, r_url_replay
from emission e
join (select #prev := 0, #rank := 1) q
inner join replay r
on r.r_e_id = e.e_id
order by e.e_tv_id asc, r.r_date desc
) q
) qq
where rank <=3 ;
demo here
I'm migrating a database from one application to another. In the first one I've two tables: proyectos and presupuestos. A row in 'proyectos' can have one or more rows in 'presupuestos'.
The new application has a field in presupuestos that is made concatenating the code of the proyect with the number of 'presupuesto' of this proyect. That's what I don't know how to do it.
My tables are like:
Proyectos:
+--------------+------------------+
| proyectos_id | proyectos_codigo |
+--------------+------------------+
| 1 | E+-00001 |
| 2 | E+-00002 |
| 3 | E+-00003 |
| 4 | E+-00004 |
| 5 | E+-00005 |
+--------------+------------------+
Presupuestos:
+-----------------+--------------+
| presupuestos_id | proyectos_id |
+-----------------+--------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 3 |
| 6 | 3 |
| 7 | 3 |
| 8 | 4 |
| 9 | 4 |
| 10 | 5 |
+-----------------+--------------+
I've tried with this query:
select presupuestos_id, p.proyectos_id, concat(pr.proyectos_codigo,'_1') from presupuestos p join proyectos pr on p.proyectos_id = pr.proyectos_id
Which result is:
+-----------------+--------------+----------------------------------+
| presupuestos_id | proyectos_id | concat(pr.proyectos_codigo,'_1') |
+-----------------+--------------+----------------------------------+
| 1 | 1 | E+-00001_1 |
| 2 | 1 | E+-00001_1 |
| 3 | 1 | E+-00001_1 |
| 4 | 2 | E+-00002_1 |
| 5 | 3 | E+-00003_1 |
| 6 | 3 | E+-00003_1 |
| 7 | 3 | E+-00003_1 |
| 8 | 4 | E+-00004_1 |
| 9 | 4 | E+-00004_1 |
| 10 | 5 | E+-00005_1 |
+-----------------+--------------+----------------------------------+
But obviusly, It doesn't what I want. My desired result is:
+-----------------+--------------+----------------------------------+
| presupuestos_id | proyectos_id | some code |
+-----------------+--------------+----------------------------------+
| 1 | 1 | E+-00001_1 |
| 2 | 1 | E+-00001_2 |
| 3 | 1 | E+-00001_3 |
| 4 | 2 | E+-00002_1 |
| 5 | 3 | E+-00003_1 |
| 6 | 3 | E+-00003_2 |
| 7 | 3 | E+-00003_3 |
| 8 | 4 | E+-00004_1 |
| 9 | 4 | E+-00004_2 |
| 10 | 5 | E+-00005_1 |
+-----------------+--------------+----------------------------------+
Try this :
SELECT presupuestos_id, p.proyectos_id,
CONCAT(pr.proyectos_codigo,'_',
(CASE p.proyectos_id
WHEN #p_id
THEN #rownumber := #rownumber + 1
ELSE #rownumber := 1 AND #p_id := p.proyectos_id END)
)AS result
FROM presupuestos p
JOIN proyectos pr ON p.proyectos_id = pr.proyectos_id
JOIN (SELECT #rownumber:=0, #p_id:='') AS t
This should do what you want, although the answer by RubahMalam looks better... :
SELECT a.presupuestos_id, a.proyectos_id, concat(p.proyectos_codigo,'_', count(*)) as "Some code"
FROM (
SELECT pr.presupuestos_id, pr.proyectos_id
FROM Presupuestos pr JOIN Proyectos p ON pr.proyectos_id = p.proyectos_id
) a
JOIN (
SELECT pr.presupuestos_id, pr.proyectos_id
FROM Presupuestos pr JOIN Proyectos p ON pr.proyectos_id = p.proyectos_id
) b
ON a.proyectos_id = b.proyectos_id AND a.presupuestos_id >= b.presupuestos_id
JOIN Proyectos p ON a.proyectos_id = p.proyectos_id
GROUP BY a.proyectos_id, a.presupuestos_id, p.proyectos_codigo
Sample SQL Fiddle
Is there a way in SQL (MySQL) to do a "round robin" ORDER BY on a particular field?
As an example, I would like to take a table such as this one:
+-------+------+
| group | name |
+-------+------+
| 1 | A |
| 1 | B |
| 1 | C |
| 2 | D |
| 2 | E |
| 2 | F |
| 3 | G |
| 3 | H |
| 3 | I |
+-------+------+
And run a query that produces results in this order:
+-------+------+
| group | name |
+-------+------+
| 1 | A |
| 2 | D |
| 3 | G |
| 1 | B |
| 2 | E |
| 3 | H |
| 1 | C |
| 2 | F |
| 3 | I |
+-------+------+
Note that the table may have many rows, so I can't do the ordering in the application. (I'd obviously have a LIMIT clause as well in the query).
I'd try something like:
SET #counter = 0;
SELECT (#counter:=#counter+1)%3 as rr, grp, name FROM table ORDER by rr, grp
What you can do is create a temporary column in which you create sets to give you something like this:
+-------+------+-----+
| group | name | tmp |
+-------+------+-----+
| 1 | A | 1 |
| 1 | B | 2 |
| 1 | C | 3 |
| 2 | D | 1 |
| 2 | E | 2 |
| 2 | F | 3 |
| 3 | G | 1 |
| 3 | H | 2 |
| 3 | I | 3 |
+-------+------+-----+
To learn how to create the sets, have a look at this question/answer.
Then its a simple
ORDER BY tmp, group, name
You can use MySQL variables to do this.
SELECT grp, name, #row:=#row+1 from table, (SELECT #row:=0) r ORDER BY (#row % 3);
+------+------+--------------+
| grp | name | #row:=#row+1 |
+------+------+--------------+
| 1 | A | 1 |
| 2 | D | 4 |
| 3 | G | 7 |
| 1 | B | 2 |
| 2 | E | 5 |
| 3 | H | 8 |
| 1 | C | 3 |
| 2 | F | 6 |
| 3 | I | 9 |
+------+------+--------------+