MySQL Update Sorted Number - mysql

I have MYSQL data like this
id | number
1 | 3
4 | 4
7 | 7
10 | 5
11 | 6
I have the database like that, and how to update the number so it will be sorted incremental?
Which mean the result will be like this
id | number
1 | 1
4 | 2
7 | 3
10 | 4
11 | 5
i updated the question so there will be no confusion in id and since id will be not consecutive

set #val = 0;
update table_name set number = (#val:=#val+1);
This would work even if table is:
id | number
1 | 3
4 | 4
7 | NULL
10 | 5
11 | NULL
to be like this:
id | number
1 | 1
4 | 2
7 | 3
10 | 4
11 | 5

update table set number=id where 1

Try this:
SET #idrank = 0;
SET #numrank = 0;
UPDATE
tbl a
INNER JOIN
(
SELECT id, #idrank:=#idrank+1 AS id_rank
FROM tbl
ORDER BY id
) b ON a.id = b.id
INNER JOIN
(
SELECT number, #numrank:=#numrank+1 AS number_rank
FROM tbl
ORDER BY number
) c ON b.id_rank = c.number_rank
SET
a.number = c.number;
This will account for gaps and irregularities in the number field as well as duplicates. Say the entire data set was something like:
id | number
---------------
2 | 534
3 | 421
6 | 2038
7 | 41
10 | 5383
11 | 5
12 | 933
15 | 43
The resulting table set after the update will be:
id | number
---------------
2 | 5
3 | 41
6 | 43
7 | 421
10 | 534
11 | 933
12 | 2038
15 | 5383
Explanation:
It basically takes the ascending ranks of each field separately and joins on the ranks so that the ordered id is matched up with corresponding ordered number.
The first INNER JOIN subselect will look like this:
id | id_rank
---------------
2 | 1
3 | 2
6 | 3
7 | 4
10 | 5
11 | 6
12 | 7
15 | 8
Then the second INNER JOIN subselect will like this:
number | number_rank
---------------
534 | 5
421 | 4
2038 | 7
41 | 2
5383 | 8
5 | 1
933 | 6
43 | 3
Then when you join the two subselects on id_rank = number_rank, you line the ascending order of the two fields up. Once you have that, updating becomes a simple matter of setting the table's number = the second joined table's number.

Related

Latest datetime from unique mysql index

I have a table. It has a pk of id and an index of [service, check, datetime].
id service check datetime score
---|-------|-------|----------|-----
1 | 1 | 4 |4/03/2009 | 399
2 | 2 | 4 |4/03/2009 | 522
3 | 1 | 5 |4/03/2009 | 244
4 | 2 | 5 |4/03/2009 | 555
5 | 1 | 4 |4/04/2009 | 111
6 | 2 | 4 |4/04/2009 | 322
7 | 1 | 5 |4/05/2009 | 455
8 | 2 | 5 |4/05/2009 | 675
Given a service 2 I need to select the rows for each unique check where it has the max date. So my result would look like this table.
id service check datetime score
---|-------|-------|----------|-----
6 | 2 | 4 |4/04/2009 | 322
8 | 2 | 5 |4/05/2009 | 675
Is there a short query for this? The best I have is this, but it returns too many checks. I just need the unique checks at it's latest datetime.
SELECT * FROM table where service=?;
First you need find out the biggest date for each check
SELECT `check`, MAX(`datetime`)
FROM YourTable
WHERE `service` = 2
GROUP BY `check`
Then join back to get the rest of the data.
SELECT Y.*
FROM YourTable Y
JOIN ( SELECT `check`, MAX(`datetime`) as m_date
FROM YourTable
WHERE `service` = 2
GROUP BY check) as `filter`
ON Y.`service` = `filter`.service
AND Y.`datetime` = `fiter`.m_date
WHERE Y.`service` = 2

What is optimal MySQL statement to select rows from same table that have some ids but not others?

We need to select all segments_id, em_id from the following table mytable that have a segments_id of 5 or 8 but not 1 or 7. To be clearer after comments made below, the result will be a set that includes all rows of segments_id, em_id where em_id has segments_id of 5 or 8 BUT not 1 or 7.
+-------------+-------+
| segments_id | em_id |
+-------------+-------+
| 1 | 8 |
| 1 | 17 |
| 5 | 2 |
| 5 | 4 |
| 5 | 5 |
| 5 | 16 |
| 5 | 17 |
| 7 | 4 |
| 7 | 5 |
| 7 | 8 |
| 7 | 16 |
| 8 | 4 |
| 8 | 6 |
| 8 | 8 |
| 8 | 18 |
| 18 | 6 |
| 18 | 99 |
+-------------+-------+
The result should be:
+-------------+-------+
| segments_id | em_id |
+-------------+-------+
| 5 | 2 |
| 8 | 6 |
| 8 | 16 |
+-------------+-------+
We need to avoid using IN clause because this can scale to millions of rows.
I understand this will involve a join on itself and/or a subquery but I'm not seeing it. I saw this post Stackoverflow: Selecting rows from a table that have the same value for one field but cannot see the solution.
You can use a LEFT JOIN to eliminate all em_id which has a segment_id that is 1 OR 7:
SELECT m.segments_id, m.em_id
FROM myTable as m
LEFT JOIN (SELECT * FROM myTable WHERE (segments_id=1 OR segments_id=7)) as n
ON m.em_id=n.em_id
WHERE n.segments_id IS NULL
GROUP BY m.em_id;
See SQLfiddle here.
If it is 5 AND 8 you want to keep and all the rest should be eliminated, then you can tweak one of your WHERE clauses like this:
SELECT m.segments_id, m.em_id
FROM myTable as m
LEFT JOIN (SELECT * FROM myTable WHERE NOT (segments_id=5 OR segments_id=8)) as n
ON m.em_id=n.em_id
WHERE n.segments_id IS NULL
GROUP BY m.em_id;
SQLfiddle for the second query is here.
And if it is only 5 AND 8 you want to keep and 1 AND 7 you want to eliminate, you can use this (however in this case, the answer given by #lad2025 might be a better choice):
SELECT m.segments_id, m.em_id
FROM myTable as m
LEFT JOIN (SELECT * FROM myTable WHERE (segments_id=1 OR segments_id=7)) as n
ON m.em_id=n.em_id
WHERE (n.segments_id IS NULL AND (m.segments_id=5 OR m.segments_id=8))
GROUP BY m.em_id;
Pls. check third SQLfiddle with an improved set here.
Using aggregation:
SELECT segments_id,em_id -- GROUP_CONCAT(segments_id) AS segments_ids
FROM mytable
GROUP BY em_id
HAVING SUM(segments_id IN (8,5)) > 0
AND SUM(segments_id IN (1,7)) = 0;
SqlFiddleDemo
Output:
╔══════════════╦═══════╗
║ segments_id ║ em_id ║
╠══════════════╬═══════╣
║ 5 ║ 2 ║
║ 8 ║ 6 ║
║ 8 ║ 18 ║
╚══════════════╩═══════╝
Not sure what you are asking for here. You tell us you want a select all but the results that you posted do not show all records that satisfy your conditions. Please elaborate on the conditions if you meant to exclude some records where segments_id = 5 or 8 and not 1 or 7.
SELECT segments_id,em_id
FROM mytable
WHERE ( segments_id = 5 OR segments_id = 8 )
AND segments_id != 1
AND segments_id != 7;
This will work!

MySQL - Get row with the maximum HISTORY ID for COMPONENT IDs in non-existing months

I have a table INVENTORY which consists of inventory items. I have the following table structure:
INSTALLATION_ID
COMPONENT_ID
HISTORY_ID
ON_STOCK
LAST_CHANGE
I need to obtain the row with the max HISTORY ID for records for which the spcified LAST_CHANGE month doesn't exist.
Each COMPONENT_ID and INSTALLATION_ID can occur multiple times, they are distinguished by their respective HISTORY_ID
Example:
I have the following records
COMPONENT_ID | INSTALLATION_ID | HISTORY_ID | LAST_CHANGE
1 | 100 | 1 | 2013-01-02
1 | 100 | 2 | 2013-02-01
1 | 100 | 3 | 2013-04-09
2 | 100 | 1 | 2013-02-22
2 | 100 | 2 | 2013-03-12
2 | 100 | 3 | 2013-07-07
2 | 100 | 4 | 2013-08-11
2 | 100 | 5 | 2013-09-15
2 | 100 | 6 | 2013-09-29
3 | 100 | 1 | 2013-02-14
3 | 100 | 2 | 2013-09-23
4 | 100 | 1 | 2013-04-17
I am now trying to retrieve the rows with the max HISTORY ID for each component but ONLY for COMPONENT_IDs in which the specifiec month does not exists
I have tried the following:
SELECT
INVENTORY.COMPONENT_ID,
INVENTORY.HISTORY_ID
FROM INVENTORY
WHERE INVENTORY.HISTORY_ID = (SELECT
MAX(t2.HISTORY_ID)
FROM INVENTORY t2
WHERE NOT EXISTS
(
SELECT *
FROM INVENTORY t3
WHERE MONTH(t3.LAST_CHANGE) = 9
AND YEAR(t3.LAST_CHANGE)= 2013
AND t3.HISTORY_ID = t2.HISTORY_ID
)
)
AND INVENTORY.INSTALLATION_ID = 200
AND YEAR(INVENTORY.LAST_CHANGE) = 2013
The query seems to have correct syntax but it times out.
In this particular case, i would like to retrieve the maximum HISTORY_ID for all components except for those that have records in September.
Because I need to completely exclude rows by their month, i cannot use NOT IN, since they will just suppress the records for september but the same component could show up with another month.
Could anybody give some pointers? Thanks a lot.
If I understand correctly what you want you can do it like this
SELECT component_id, MAX(history_id) history_id
FROM inventory
WHERE last_change BETWEEN '2013-01-01' AND '2013-12-31'
AND installation_id = 100
GROUP BY component_id
HAVING MAX(MONTH(last_change) = 9) = 0
Output:
| COMPONENT_ID | HISTORY_ID |
|--------------|------------|
| 1 | 3 |
| 4 | 1 |
If you always filter by installation_id and a year of last_change make sure that you have a compound index on (installation_id, last_change)
ALTER TABLE inventory ADD INDEX (installation_id, last_change);
Here is SQLFiddle demo

Remove duplicates from one column keeping whole rows

id | userid | total_points_spent
1 | 1 | 10
2 | 2 | 15
3 | 2 | 50
4 | 3 | 5
5 | 1 | 15
With the above table, I would first like to remove duplicates of userid keeping the rows with the largest total_points_spent, like so:
id | userid | total_points_spent
3 | 2 | 50
4 | 3 | 5
5 | 1 | 15
And then I would like to sum the values of total_points_spent, which would be the easy part, resulting in 70.
I am not really sure the "remove" you meant is to delete or to select. Here is the query for select only max totalpointspend record respectively.
SELECT tblA.*
FROM ( SELECT userid, MAX(totalpointspend) AS maxtotal
FROM tblA
GROUP BY userid ) AS dt
INNER JOIN tblA
ON tblA.userid = dt.userid
AND tblA.totalpointspend = dt.maxtotal
ORDER BY tblA.userid

SQL with specific LIMIT

I have the next example table:
id | user_id | data
-------------------
1 | 1 | 10
2 | 2 | 10
3 | 2 | 10
4 | 1 | 10
5 | 3 | 10
6 | 4 | 10
7 | 4 | 10
8 | 5 | 10
9 | 5 | 10
10 | 2 | 10
11 | 6 | 10
12 | 3 | 10
13 | 1 | 10
I need to create a SELECT query, that LIMITS my data. For example, I have a limit range (1, 3) (page number = 1, row count = 3). It should selects rows with first 3 unique user_id. And if there are some rows in the end of table with this first user_id's, they should be included to the result. LIMIT statement is bad for this query, because I can get more than 3 rows. Output for my limit should be:
id | user_id | data
-------------------
1 | 1 | 10
2 | 2 | 10
3 | 2 | 10
4 | 1 | 10
5 | 3 | 10
10 | 2 | 10
12 | 3 | 10
13 | 1 | 10
Can you help me to generate this query?
How about:
SELECT *
FROM table
WHERE user_id IN
(SELECT distinct(user_id) FROM table order by user_id LIMIT 3);
What about something like this?
SELECT * FROM table WHERE user_id BETWEEN (number) AND (number+row count)
I know it isn't working but you should be able to make it work ^^
The sample code below can be used for Oracle & Mysql. (use TOP for SQL Server & Sybase)
You get all the results from your table (t1) that match the top 3 user_id (t2) (check the MySQL manual for the limit function)
SELECT *
FROM exampletable t1
INNER JOIN (
SELECT DISTINCT user_id
FROM exampletable
ORDER BY user_id
LIMIT 0,3 -- this is the important part
) AS t2 ON t1.user_id = t2.user_id
ORDER BY id
For the next 3 id's change the limit 0,3 to limit 3,6.