mysql sequence swapping values - mysql

Database table
id serial account speeddialsort dest
107 155 501 1 020341542
115 155 501 2 004407152222
116 155 501 3 00951242454
117 155 501 4 0794245544
118 266 700 1 004465652212
119 266 700 2 0044845482
Data presented to user
This a list of account's 501 speed dial slots.
I can send the speeddialsort and dest if required from a form, what sql method can I then use to manage user editing of the speed dial order.
The order is to be moved up or down
speeddialsort dest
#1 020341542
#2 004407152222
#3 00951242454
#4 0794245544
For example user selects speed dial #3 be moved up. The speeddialsort of #2 and #3 will need to be swapped

I asume speeddialsort is UNIQUE and dest isn't?
Asume $int_short to be supplied sort_id and $int_previous_sort to be the value is was before:
INSERT INTO table (speeddialsort, dest)
SELECT speeddialsort, dest
FROM (SELECT {$int_sort} AS speeddialsort, dest
FROM table
WHERE speeddialsort = {$int_previous_sort}
UNION ALL
SELECT {$int_previous_sort}, dest
FROM table
WHERE speeddialsort = {$int_sort})
ON DUPLICATE KEY UPDATE dest = VALUES(dest)
In case both are UNIQUE, it'd be easier to simply remove and readd them. That, or:
INSERT INTO table (speeddialsort, dest)
SELECT speeddialsort, dest
FROM (SELECT {$int_sort} AS speeddialsort, NULL AS dest
UNION ALL
SELECT {$int_previous_sort}, NULL
UNION ALL
SELECT {$int_sort}, dest
FROM table
WHERE speeddialsort = {$int_previous_sort}
UNION ALL
SELECT {$int_previous_sort}, dest
FROM table
WHERE speeddialsort = {$int_sort})
ON DUPLICATE KEY UPDATE dest = VALUES(dest)
Should work aswell.

Move Up:
UPDATE my_table AS t1 SET t1.dest =
IFNULL( ( SELECT t2.dest FROM my_table AS t2
WHERE t2.speeddialsort IN( {$i}, {$i-1} ) AND
t2.account = $account AND t2.dest <> t1.dest ), t1.dest )
WHERE t1.speeddialsort IN( {$i}, {$i-1} ) AND t1.account = {$account}
to Move Down just replace $i-1s with $i+1
($i is the speeddialsort you want to move, $account is the account id)

I create a table and the row serial is made in a continuous sequence by using
mysql user defined variable.
ID serial
101 1
103 2
104 3
110 4
In this to move the item with serial 4 to 2
SET #a = 2;
UPDATE tableName SET serial = #a:=#a + 1 WHERE serial >= 2 AND serial < 4
ORDER BY serial DESC;
UPDATE tableName SET serial = 2 WHERE ID = 1;
This query will add 1 to all the serial values less than 4 and greater than 2 and then update the row with serial 4 with value 2.
And to move item 2 to 4
SET #b = 4;
UPDATE tableName SET ord = #b:=#b - 1 WHERE serial > 2 AND serial < (4 + 1)
ORDER BY serial DESC;
UPDATE tableName SET serial = 4 WHERE ID = 1 ;
I am not talking about Auto Increment.In my case I need to order the values as user required.So i cannot use Auto increment.

Related

MySQL Putting in duplicate id's

I'm trying to run an UPDATE query that uses the same table and I'm getting an error saying "1093 - Table 'queues_monitor_times' is specified twice, both as a target for 'UPDATE' and as a separate source for data".
UPDATE queues_monitor_times
SET queue_id = IF((
SELECT id
FROM queues_monitor_times
INNER JOIN(
SELECT pcc_group, pcc, gds, queue, category, `name`
FROM queues_monitor_times
GROUP BY pcc_group, pcc, gds, queue, category, `name`
HAVING COUNT(id) > 1
)temp ON queues_monitor_times.pcc_group = temp.pcc_group AND
queues_monitor_times.pcc = temp.pcc AND
queues_monitor_times.gds = temp.gds AND
queues_monitor_times.queue = temp.queue AND
queues_monitor_times.category = temp.category AND
queues_monitor_times.`name` = temp.`name`), 1, id)
WHERE
id NOT IN (SELECT MIN(id) FROM queues_old GROUP BY pcc_group, pcc, gds, queue, category, `name`);
I ran the select query by itself and it showed all the rows that were duplicates, which is what I wanted. I want queue_id to be set with the lowest duplicate row's id if the row is a duplicate or the row id if it is not.
Example of what the query should do:
id dup_id name value
1 1 John 13
2 2 John 13
3 3 Sally 6
4 4 Frank 4
5 5 Sally 6
And after running the query it will turn into
id dup_id name value
1 1 John 13
2 1 John 13
3 3 Sally 6
4 4 Frank 4
5 3 Sally 6
Please advise and thank you for your help.
I was able to solve my problem. Thanks for all your help!
UPDATE queues_monitor_times
SET queue_id = (
SELECT
id
FROM
queues_old
WHERE
queues_old.pcc_group = queues_monitor_times.pcc_group
AND queues_old.pcc = queues_monitor_times.pcc
AND queues_old.gds = queues_monitor_times.gds
AND queues_old.queue = queues_monitor_times.queue
AND queues_old.category = queues_monitor_times.category
AND queues_old.`name` = queues_monitor_times.`name`
GROUP BY pcc_group, pcc, gds, queue, category, `name`
HAVING COUNT(id) > 1)
WHERE
id NOT IN (SELECT MIN(id) FROM queues_old GROUP BY pcc_group, pcc, gds, queue, category, `name`);
For those that will want to use this in the future, queues_monitor_times table and queues_old table have the exact same data.

In MySql, how to create a sequential set of values based on a record id where a specific related_id is available

What I am attempting to do is populate a value of 1, 2, 3, 4 based on the sequence of the primary key id, from low to high, where a repetitive value is present. Also, only doing this update based on a class value of 'jt'.
Example:
ID abstract_id class jump_no
101 123 st null
102 123 st null
103 123 jt 1
104 123 jt 2
105 205 jt 1
106 205 jt 2
107 205 jt 3
108 391 st null
Currently my table has all null value for the jump_no column. I am trying to populate that sequence, per abstract_id grouping but only with a class value of 'jt'.
So the 1, 2, 3, 4 "counter" restarts for every new abstract_id.
There are a couple ways to do this. One uses correlated subqueries. Another that I use more often uses user-defined variables:
update yourtable y
join (
select id, abstract_id,
case abstract_id
when #prev_abstract_id
then #jump_no := #jump_no + 1
else #jump_no := 1 AND #prev_abstract_id := abstract_id end jump_no
from yourtable join (select #jump_no:=0, #prev_abstract_id:=0) t
order by id, abstract_id) t on y.id = t.id
set y.jump_no = t.jump_no;
Online SQL Example

SQL Query, how to select a interval where the next value is current value +1, identifying the next gap and leave everything else untouched?

I'm making a program on java using sql querys and i'd like to update a sequence of ids adding 1 to each, but only in the sequence interval.
Let's say i have a table like this:
1 - a | 2 - b | 3 - c | 5 - e | 6 - f
And i'd like to "push" a's ID and subsequents forward by 1, but only while the difference between one another is still 1. The result would be like this:
2 - a | 3 - b | 4 - c | 5 - e | 6 - f
I know it is possible to do programatically, but is there a way to do this with SQL querys? If not, what would be the best way to do this?
Thanks in advance.
Edit: Found the answer thanks to Thorsten Kettner, my query ended up like this:
update pair set id = id + 1
where id >= 1
and id <
(
select min(id)
from (select * from pair) as gap
where gap.id > 1 and not exists
(
select *
from (select * from pair) as oneless
where oneless.id = gap.id - 1
)
)
order by id desc
If you know where the gap is that you want closed (ID 4 in your case) use this:
update mytable set id = id + 1 where id < 4;
If you don't know where the gap is, find it:
select min(id) - 1
from mytable
where not exists
(
select *
from mytable oneless
where oneless.id = mytable.id - 1
);
We can combine both statments now to do the update:
update mytable set id = id + 1
where id <
(
select min(id) - 1
from mytable
where not exists
(
select *
from mytable oneless
where oneless.id = mytable.id - 1
)
);
Let's call your table Pair and the two columns Key and Value. Your query would be something like this:
update p1
set Key = p1.Key + 1
from Pair as p1
inner join Pair as p2
on p2.Key = p1.Key + 1
PS. I'm assuming your result has a typo because after the update, f should have a value of 7.

Count first occurence with column value ordered by another column

I have an assigns table with the following columns:
id - int
id_lead - int
id_source - int
date_assigned - int (this represents a unix timestamp)
Now, lets say I have the following data in this table:
id id_lead id_source date_assigned
1 20 5 1462544612
2 20 6 1462544624
3 22 6 1462544615
4 22 5 1462544626
5 22 7 1462544632
6 25 6 1462544614
7 25 8 1462544621
Now, lets say I want to get a count of the rows whose id_source is 6, and is the first entry for each lead (sorted by date_assigned asc).
So in this case, the count would = 2, because there are 2 leads (id_lead 22 and 25) whose first id_source is 6.
How would I write this query so that it is fast and would work fine as a subquery select? I was thinking something like this which doesn't work:
select count(*) from `assigns` where `id_source`=6 order by `date_assigned` asc limit 1
I have no idea how to write this query in an optimal way. Any help would be appreciated.
Pseudocode:
select rows
with a.id_source = 6
but only if
there do not exist any row
with same id_lead
and smaller date_assigned
Translate it to SQL
select * -- select rows
from assigns a
where a.id_source = 6 -- with a.id_source = 6
and not exists ( -- but only if there do not exist any row
select 1
from assigns a1
where a1.id_lead = a.id_lead -- with same id_lead
and a1.date_assigned < a.date_assigned -- and smaller date_assigned
)
Now replace select * with select count(*) and you'll get your result.
http://sqlfiddle.com/#!9/3dc0f5/7
Update:
The NOT-EXIST query can be rewritten to an excluding LEFT JOIN query:
select count(*)
from assigns a
left join assigns a1
on a1.id_lead = a.id_lead
and a1.date_assigned < a.date_assigned
where a.id_source = 6
and a1.id_lead is null
If you want to get the count for all values of id_source, the folowing query might be the fastest:
select a.id_source, count(1)
from (
select a1.id_lead, min(a1.date_assigned) date_assigned
from assigns a1
group by a1.id_lead
) a1
join assigns a
on a.id_lead = a1.id_lead
and a.date_assigned = a1.date_assigned
group by a.id_source
You still can replace group by a.id_source with where a.id_source = 6.
The queries need indexes on assigns(id_source) and assigns(id_lead, date_assigned).
Simple query for that would be
check here http://sqlfiddle.com/#!9/8666e0/7
select count(*) from
(select * from assigns group by id_lead )t
where t.id_source=6

Mysql combine rows?

I have a table with itemid|fieldid|value and i'm trying to setup a query that will combine some data and return a mathc percentage along with the result. for example, some data could be
itemid fieldid value
19 193 1
45 193 1
37 201 6
25 201 1
45 201 6
19 201 6
19 201 5
Now i want for example, to get all the rows with fieldid = 193 AND value = 1 as well as the rows with fieldid = 201 AND value = 6. The ideal result would be something like :
itemid, percentage getting 100% for all itemids which match both conditions and 50% for all that match one. I have this query working for doing the above over multiple columns but it will not work here
select id,user_class,admin, (
if (admin = 1,1,0)+
if (user_class = 'SA',1,0)
)/2*100 as the_percent
from users
WHERE
admin = 1 OR user_class = 'P'
GROUP BY id
order by the_percent DESC
Also i got the following for absolute matching
SELECT users.id FROM users WHERE
users.id IN
(
SELECT DISTINCT itemid FROM extra_field_values
INNER JOIN (SELECT DISTINCT itemid FROM extra_field_values WHERE fieldid = 201 AND value = 6 ) a1 USING (itemid)
INNER JOIN (SELECT DISTINCT itemid FROM extra_field_values WHERE fieldid = 193 AND value = 1 ) a2 USING (itemid)
)
but combining the two seems to be a bit of a puzzle to me
I think you might be able to make use of a UNION and selecting from a table subquery to make this happen. Perhaps something along the lines of:
SELECT itemid, count(*)/2*100 AS percent FROM
( SELECT itemid FROM extra_field_values WHERE fieldid = 201 AND value = 6
UNION ALL
SELECT itemid FROM extra_field_values WHERE fieldid = 193 AND value = 1 ) AS t
GROUP BY itemid;
It's been a while since I've done anything complex in mysql, and I threw this together in notepad so my syntax could be off :) But basically we create a view of the matching ids, then from that table create our statistics. (You'll also want to do some performance evaluation as well to see how it stacks up compared to doing multiple queries as well).