Find last value from one out of 3 row groups - mysql

I want to find a specific value from this table; the last value for each ElEnd that is has ItemNumber 2:
ID | ID2 | Item1 | Item2 | Item3 | Element | ItemNum | ElStart | ElEnd
===================================================================
1 | 1 | rock | n | roll | r | 1 | 23.212 | 23.222
2 | 1 | rock | n | roll | o | 1 | 23.222 | 23.256
3 | 1 | rock | n | roll | c | 1 | 23.256 | 23.277
4 | 1 | rock | n | roll | k | 1 | 23.277 | 23.290
5 | 1 | rock | n | roll | n | 2 | 23.290 | 23.321
6 | 1 | rock | n | roll | r | 3 | 23.321 | 23.331
7 | 1 | rock | n | roll | o | 3 | 23.331 | 23.434
8 | 1 | rock | n | roll | l | 3 | 23.434 | 23.456
9 | 1 | rock | n | roll | l | 3 | 23.456 | 23.567
10 | 2 | a | tiny | rock | a | 1 | 23.567 | 23.678
11 | 2 | a | tiny | rock | t | 2 | 23.678 | 23.789
12 | 2 | a | tiny | rock | i | 2 | 23.789 | 23.890
13 | 2 | a | tiny | rock | n | 2 | 23.890 | 23.901
14 | 2 | a | tiny | rock | y | 2 | 23.901 | 24.123
15 | 2 | a | tiny | rock | r | 3 | 24.123 | 24.234
16 | 2 | a | tiny | rock | o | 3 | 24.234 | 24.345
17 | 2 | a | tiny | rock | c | 3 | 24.345 | 24.456
18 | 2 | a | tiny | rock | k | 3 | 24.456 | 24.567
So in the case of this example table, I want to select 23.321 and 24.123. I later want to use these values in an UPDATE to copy them to a new column Item2ElementEnd.
I've tried a number of queries that use subselect or UNION, but none of them were efficient - they were all running so slowly that I had to stop them (my table has about 600.000 entries).
This is a query which gives me the wrong value (ElEnd for ItemNum 3 rather than 2):
select ID2, Item2, max(ElEnd)
from t1
group by ID2;
This is an example query which didn't work because it was running WAY too slowly (I had to abort):
select Item2, ElStart, ElEnd
from t1
where ItemNum = "2"
and ElStart = (select max(ElStart) from t1 as f where f.Item2 = t1.Item2);
How can I do this most efficiently?

I have now found a (surprisingly simple) solution using this query:
select ID, ID2, item2, max(ElEnd), ItemNum
from t1
WHERE ItemNum = 2
group by ID2, ItemNum;

Related

SQL query to find the bus travelling through route

Having a table name route, contains the bus_id,stop_name and position(it is the sequence of the stops).
bus travel in one way according to position
Table: route
| bus_id | stop_name | position |
|--------|-----------|----------|
| 1 | Stop_1 | 1 |
| 1 | Stop_2 | 2 |
| 1 | Stop_3 | 3 |
| 1 | Stop_4 | 4 |
| 1 | Stop_5 | 5 |
| 1 | Stop_6 | 6 |
| 1 | Stop_7 | 7 |
| 2 | Ramdom_1 | 1 |
| 2 | Ramdom_2 | 2 |
| 2 | Stop_3 | 3 |
| 2 | Stop_4 | 4 |
| 2 | Stop_5 | 5 |
| 2 | Stop_6 | 6 |
| 2 | Ramdom_3 | 7 |
Now need to find the bus_id which go from stop_3 to stop_6 i.e bus_id = 1 and 2
examples:\
from stop_1 to stop_6 = 1\
from stop_6 to Ramdom_3 = 2\
from stop_6 to stop_1 = no bus found\
Need to MYSQL query to find the above data
database used Server version: 10.4.21-MariaDB (xamp)
Select a.*, b.*
From route a
Join route b on a. bus_id=b.bus_id
Where a.position <b.position
And a.name=[stopname] and b.name=.
[stopname]

Mysql 2 select staments with value from statement 1 used in statement 2

How to join these to in one sql statement?
I have these 2 simple tables.
3_Referee_Matches
+------------------------------------+
| ID | CountryCode | RefereeUrlCode |
| 1 | eng | mike-jean |
| 2 | eng | mike-jean |
| 3 | eng | mike-jean |
| 4 | eng | mike-jean |
| 5 | spa | hulo-pape |
| 6 | ita | enri-tolsi |
| 7 | ita | enra-ean |
| 8 | ita | enra-ean |
+------------------------------------+
3_Players
+----------------------------------------------------+
| ID | MatchID | Name | PlayerUrlCode | Yellow |
| 1 | 1 | Mike Bell | mike-bell | 1 |
| 2 | 2 | Mike Bell | mike-bell | 1 |
| 3 | 3 | Thoms Tim | thoms-tim | 1 |
| 4 | 4 | Jean Claod | jean-claod | 0 |
| 5 | 33 | Thoms Tim | thoms-tim | 1 |
| 6 | 44 | Fis Most | fis-most | 0 |
| 7 | 54 | Geni Toens | geni-toens | 1 |
| 8 | 67 | Geni Toens | geni-toens | 1 |
+----------------------------------------------------+
Today i use these 2 select. But need help to combine them into one.
select 1:
SELECT rm.*, p.PlayerUrlCode AS VALUEtoBEusedAGAIN, COUNT(p.ID) AS YellowCounter
FROM 3_Referee_Matches rm
JOIN 3_Players p ON rm.ID = p.MatchID
WHERE rm.CountryCode = 'eng' AND rm.RefereeUrlCode = 'mike-jean'
AND p.Yellow>0
GROUP BY p.Name
select 2:
SELECT COUNT(rm.ID) AS Counter
FROM 3_Referee_Matches rm
JOIN 3_Players p ON rm.ID = p.MatchID
WHERE rm.RefereeUrlCode='mike-jean'
AND p.PlayerUrlCode='VALUEtoBEusedAGAIN'
Result should be like this:
+--------------------------------------+
| Name | YellowCounter | Counter |
| Mike Bell | 2 | 2 |
| Jean Claod | 1 | 1 |
+--------------------------------------+
Showing that Mike Bell Got 2 yellow cards in 2 matches.
Your first query is nearly there. First, remove the extraneous columns from the select clause. count the number of "players" (really player information for each match) and sum their yellow cards.
select
p.name,
sum(yellow) as YellowCounter,
count(p.id) as Counter
from 3_Referee_Matches rm
join 3_Players p on rm.ID = p.MatchID
where rm.CountryCode = 'eng'
and rm.RefereeUrlCode = 'mike-jean'
group by p.name;
+------------+---------------+---------+
| name | YellowCounter | Counter |
+------------+---------------+---------+
| Mike Bell | 2 | 2 |
| Thoms Tim | 1 | 1 |
| Jean Claod | 0 | 1 |
+------------+---------------+---------+
I assume the example has Thoms and Jean reversed.

How to get count of combinations from database?

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

Compacting tables after normalisation

I recently increased the level of normalisation in my database, going from something like this:
+--------------------------------------+
| state_changes |
+----+-------+-----------+------+------+
| ID | Name | Timestamp | Val1 | Val2 |
+----+-------+-----------+------+------+
| 0 | John | 17:19:01 | A | X |
| 1 | Bob | 17:19:02 | E | W |
| 2 | John | 17:19:05 | E | Y |
| 3 | John | 17:19:06 | B | Y |
| 4 | John | 17:19:12 | C | Z |
| 5 | John | 17:19:15 | A | Z |
+----+-------+-----------+------+------+
To something more like this:
+-------------------------------+ +-------------------------------+
| state_changes_1 | | state_changes_2 |
+----+-------+-----------+------+ +----+-------------------+------+
| ID | Name | Timestamp | Val1 | | ID | Name | Timestamp | Val2 |
+----+-------+-----------+------+ +----+-------+-----------+------+
| 0 | John | 17:19:01 | A | | 0 | John | 17:19:01 | X |
| 1 | Bob | 17:19:02 | E | | 1 | Bob | 17:19:02 | W |
| 2 | John | 17:19:05 | E | | 2 | John | 17:19:05 | Y |
| 3 | John | 17:19:06 | B | | 3 | John | 17:19:06 | Y |
| 4 | John | 17:19:12 | C | | 4 | John | 17:19:12 | Z |
| 5 | John | 17:19:15 | A | | 5 | John | 17:19:15 | Z |
+----+-------+-----------+------+ +----+-------+-----------+------+
How could I now write a query to "compact" the two resulting tables where values are duplicated?
I want to ignore the ID field when considering row uniqueness;
I want to ignore the Timestamp when considering row uniqueness;
But fields must be sequential (under a Name,Timestamp ordering) to be considered duplicates.
The result, in this example, should be:
+-------------------------------+ +-------------------------------+
| state_changes_1 | | state_changes_2 |
+----+-------+-----------+------+ +----+-------+-----------+------+
| ID | Name | Timestamp | Val1 | | ID | Name | Timestamp | Val2 |
+----+-------+-----------+------+ +----+-------+-----------+------+
| 0 | John | 17:19:01 | A | | 0 | John | 17:19:01 | X |
| 1 | Bob | 17:19:02 | E | | 1 | Bob | 17:19:02 | W |
| 3 | John | 17:19:06 | B | | 2 | John | 17:19:05 | Y |
| 4 | John | 17:19:12 | C | | 4 | John | 17:19:12 | Z |
| 5 | John | 17:19:15 | A | +----+-------+-----------+------+
+----+-------+-----------+------+
My tables have several billion rows so I'm looking for something that takes efficiency into consideration; that said, I'm a realistic sort of person so I'm happy for the query to take an hour or two to run (including index rebuilds) if needs be.
I tried this on MySQL 5.1.58 and it seems to work with your test data.
SET #name = NULL;
SET #val1 = NULL;
UPDATE state_changes_1
SET Val1 = IF(Name=#name AND Val1=#val1, NULL, (#val1:=Val1)),
Name = (#name:=Name)
ORDER BY Name, `Timestamp`;
DELETE FROM state_changes_1 WHERE Val1 IS NULL;
Your problem is your concept of 'sequential' or consecutive duplicate doesn't exist in relational algebra so won't be able to do it in sql. You can get easily the latest timestamp of each state by doing
SELECT id, name, MAX(timestamp) ts , state FROM states
GROUP BY id, name, state
ORDER BY ts
However, you could do what you want by dumping your table into a text file and do a simple script in which ever language you are confortable with, perl, ruby python etc. Even on a million row table that could be done quiet quickly

Is there a way in SQL (MySQL) to do a "round robin" ORDER BY on a particular field?

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 |
+------+------+--------------+