using a LEFT OUTER JOIN on something COALESCED - mysql

I have this table where I only want to look at AB
ID CODE COUNT
102 AB 9
101 AB 8
100 AC 23 //not important!!!!
99 AB 7
98 AB 6
97 AB 5
96 AB 0
Conversed to this
ID NEWID CODE COUNT
102 102 AB 9
101 101 AB 8
99 100 AB 7
98 99 AB 6
97 98 AB 5
96 97 AB 0
Using this query:
SELECT t.ID, #NEWID := COALESCE(#NEWID - 1, t.ID) AS NEWID, t.CODE, t.COUNT
FROM
(SELECT ID, CODE, COUNT FROM some_table WHERE CODE = 'AB' ORDER BY ID DESC) t,
(SELECT #NEWID := NULL) _uv;
http://sqlfiddle.com/#!2/e0b8b/1/0
And now I want to count the difference of each consecutive NEWID.
So
Step 1: 9 - 8 = 1
Step 2: 8 - 7 = 1
Step 3: 7 - 6 = 1
Step 4: 6 - 5 = 1
Step 5: 5 - 0 = 5
I'm used to doing this with
LEFT OUTER JOIN some_table t2 ON t.ID = ( t2.ID + 1 )
And then taking the difference between t2.count and t.count,
but now when I'm using COALESCE, I cannot select this NEWID, so the code below does not work.
LEFT OUTER JOIN some_table t2 ON t.NEWID = ( t2.NEWID + 1 )
So how should I resolve this issue?

Oh, so that's why you needed sequential IDs. Well, you can use user variables for this, too, and you don't even need NEWID! Since you're doing stuff like this, you'd do well to read up on how user variables work.
SELECT
t.ID, t.CODE, t.COUNT,
#PREVCOUNT - t.COUNT DIFFERENCE,
#PREVCOUNT := t.COUNT -- Updates for the next iteration, so it
-- must come last!
FROM
(SELECT ID, CODE, COUNT FROM some_table WHERE CODE = 'AB' ORDER BY ID DESC) t,
(SELECT #PREVCOUNT := NULL) _uv;
SQL Fiddle

Try this:
SELECT
t1.ID as ID1,
t2.ID as ID2,
t1.CODE as CODE,
t1.COUNT as C1,
t2.COUNT as C2,
t2.COUNT - t1.COUNT as DIFF
FROM
some_table t1
INNER JOIN some_table t2 ON t1.ID < t2.ID AND t1.CODE = t2.CODE
WHERE
t1.CODE='AB'
AND NOT EXISTS
(SELECT * FROM some_table t3
INNER JOIN some_table t4 ON t3.ID < t4.ID and t3.CODE = t4.CODE
WHERE
t3.CODE='AB'
AND t1.ID = t3.ID
AND t4.ID < t2.ID
)
ORDER BY t1.ID
Another way will be to use LIMIT:
SELECT
t.ID1 AS ID,
t.CODE as CODE,
t.C2-t.C1 AS DIFF
FROM
(
SELECT
t1.ID as ID1,
t1.CODE as CODE,
t1.COUNT as C1,
(SELECT t.COUNT
FROM some_table t
WHERE t.ID > t1.ID AND t.CODE=t1.CODE
ORDER BY t.ID
LIMIT 1) as C2
FROM
some_table t1
WHERE
t1.CODE='AB'
ORDER BY t1.ID) t
ORDER BY t.ID1
http://sqlfiddle.com/#!2/e0b8b/24

Related

outer join in mysql not providing the results

Hypothetical data -
tbl1 -
id
date
value1
101
2021-01-01
200
101
2021-01-03
400
tbl2 -
id
date
value2
101
2021-01-01
600
101
2021-01-02
900
My expected result is -
id
date
value1
value2
101
2021-01-01
200
600
101
2021-01-02
NaN
900
101
2021-01-03
400
NaN
select * from (select * from tbl1 where id in
(another query)) t1
left join tbl2 as t2 on t1.id = t2.id and t1.date = t2.date
union all
select * from (select * from tbl1 where id in
(another query)) t1
right join tbl2 as t2 on t1.id = t2.id and t1.date = t2.date
where t1.id is null and t1.date is null
I am unable to figure out where am I going wrong.
I think you might be overcomplicating your union query:
SELECT t1.id, t1.date, t1.value1, t2.value2
FROM tbl1 t1
LEFT JOIN tbl2 t2 ON t1.id = t2.id AND t1.date = t2.date
UNION ALL
SELECT t2.id, t2.date, t1.value1, t2.value2
FROM tbl1 t1
RIGHT JOIN tbl2 t2 ON t1.id = t2.id AND t1.date = t2.date
WHERE t1.id IS NULL
ORDER BY id, date;
Demo
Collect all present (id, `date`) pairs then join source data to it:
SELECT id, `date`, tbl1.value1, tbl2.value2
FROM ( SELECT id, `date` FROM tbl1
UNION
SELECT id, `date` FROM tbl2 ) combined
LEFT JOIN tbl1 USING (id, `date`)
LEFT JOIN tbl2 USING (id, `date`);
fiddle
The solution assumes that (id, `date`) is unique over each separate source table. If not then some aggregation must be used (SUM or MAX, depends on the logic).

Mysql - reorder / reset position key

I have a MySQL table with position key (65,000 records). I deleted, updated some rows in the middle of the table. Now I have, for example, something like this in the position 1 - 6 - 2 - 9
id
category
position
1
1
1
2
1
6
3
2
2
4
2
9
I want to reset / reorder the position key
id
category
position
1
1
1
2
1
2
3
2
1
4
2
2
How can I reset position where category = 1
and where category = 2?
Try this:
UPDATE source_table
JOIN ( SELECT id, ROW_NUMBER() OVER (PARTITION BY category ORDER BY position) position
FROM source_table ) subquery USING (id)
SET source_table.position = subquery.position
mysql> SHOW VARIABLES LIKE "%version%"; 5.7.24 – sagittarius
UPDATE source_table
JOIN ( SELECT t1.id, COUNT(t2.id) position
FROM source_table t1
JOIN source_table t2 ON t1.category = t2.category
AND t1.position >= t2.position
GROUP BY t1.id ) subquery USING (id)
SET source_table.position = subquery.position;
fiddle
if position is duplicated everything crashes – sagittarius
UPDATE source_table
JOIN ( SELECT t1.id, COUNT(t2.id) position
FROM source_table t1
JOIN source_table t2 ON t1.category = t2.category
AND ( t1.position > t2.position
OR ( t1.position = t2.position
AND t1.id >= t2.id ))
GROUP BY t1.id ) subquery USING (id)
SET source_table.position = subquery.position;
fiddle
UPDATE source_table t1
INNER JOIN
(
SELECT id,category,position, ROW_NUMBER() OVER (PARTITION BY category
ORDER BY position) position2
FROM source_table
) t2
ON t2.id = t1.id
SET
t1.position = t2.position2
I think this code is easy to understand and apply.

How I can mix column data

I have a table table_1
id contact_id
1 500
5 89
8 35
15 458
... ...
555 38
how I can mix contact_id, result for table_1
id contact_id
1 35
5 458
8 35
15 89
... ...
555 45
You can randomly assign the contact ids using variables or row_number() (in MySQL 8+):
select t1.id, tt1.contact_id
from (select t1.*, row_number() over (order by id) as seqnum
from table_1 t1
) t1 join
(select t1.*, row_number() over (order by rand()) as seqnum
from table_1 t1
) tt1
on t1.seqnum = tt1.seqnum;
Without much difficulty (but more typing), this can be transformed to use variables in earlier versions.
You can also incorporate this into an update statement, if you want to shuffle the values permanently.
EDIT:
I think you want:
update table1 t1 join
(select t1.id, tt1.contact_id
from (select t1.*, (#rn1 := #rn1 + 1) as seqnum
from (select * table_1 order by id) t1 cross join
(select #rn1 := 0) params
) t1 join
(select t1.*, (#rn2 := #rn2 + 1) as seqnum
from (select * from table_1 order by rand()) t1 cross join
(select #rn2 := 0) params
) tt1
on t1.seqnum = tt1.seqnum
) tt1
on tt1.id = t1.id
set t1.contact_id = tt1.contact_id;

UPDATE and SELECT from same table in one query

I am trying to count the rows from table1, and depending the rows count to update a certain column. Below is the query I have tried, but am getting an arror saying that temp is not a table.
UPDATE table1 AS t1
INNER JOIN table1 AS temp ON temp.id = t1.id
SET
t1.field1 = (CASE
WHEN (SELECT COUNT(*) FROM temp WHERE temp.field1 = 1) < 100 THEN 1
WHEN (SELECT COUNT(*) FROM temp WHERE temp.field1 = 2) < 100 THEN 2
WHEN (SELECT COUNT(*) FROM temp WHERE temp.field1 = 3) < 100 THEN 3
WHEN (SELECT COUNT(*) FROM temp WHERE temp.field1 = 4) < 100 THEN 4
WHEN (SELECT COUNT(*) FROM temp WHERE temp.field1 = 5) < 100 THEN 5
END)
WHERE t1.id IN(100, 200, 300); --Example data
A couple things:
I would suggest making a temp table of the data in your case
statement, then joining that for an update.
Joining back on the table you're updating does not work.
You have a syntax error in your where clause. You don't need that
equals sign before IN.
Try:
DROP TABLE IF EXISTS temp_table1;
CREATE TEMPORARY TABLE temp_table1 AS
SELECT field1,count(*) as field_count FROM table1 group by field1;
UPDATE table1 AS t1
LEFT JOIN temp_table1 aa
ON aa.field1= t1.field1
SET t1.field1 = (CASE
WHEN aa.field1 = 1 AND aa.field_count < 100 THEN 1
WHEN aa.field1 = 2 AND aa.field_count < 100 THEN 2
WHEN aa.field1 = 3 AND aa.field_count < 100 THEN 3
WHEN aa.field1 = 4 AND aa.field_count < 100 THEN 4
WHEN aa.field1 = 5 AND aa.field_count < 100 THEN 5 END)
WHERE t1.id IN (100, 200, 300);
Following query will be helpful to you,
UPDATE table1 as t1
SET
t1.field1 = (CASE
WHEN (select p.cnt from (SELECT COUNT(*) as cnt FROM table1 t2 WHERE t2.field1= 1) as p) < 100 THEN 1
WHEN (select p.cnt from (SELECT COUNT(*) as cnt FROM table1 t2 WHERE t2.field1= 2) as p) < 100 THEN 2
WHEN (select p.cnt from (SELECT COUNT(*) as cnt FROM table1 t2 WHERE t2.field1= 3) as p) < 100 THEN 3
WHEN (select p.cnt from (SELECT COUNT(*) as cnt FROM table1 t2 WHERE t2.field1= 4) as p) < 100 THEN 4
WHEN (select p.cnt from (SELECT COUNT(*) as cnt FROM table1 t2 WHERE t2.field1= 5) as p) < 100 THEN 5
END)
WHERE t1.id IN(100, 200, 300)

MySQL select 1 row from multiple rows

Please Suggest to get single 0 type row from multiple (0 type rows) and selected row should be just before type 1 row
Emp_tbl (id,type,company_id,created_at)
1,0,121,2015-02-19 18:05
2,0,121,2015-02-19 18:15
3,0,121,2015-02-19 18:17
4,1,121,2015-02-19 19:22
5,2,121,2015-02-19 19:25
6,0,121,2015-02-19 22:05
7,0,121,2015-02-19 22:15
8,0,121,2015-02-19 22:17
9,1,121,2015-02-19 22:22
10,2,121,2015-02-19 22:25
Expected Result
3,0,121,2015-02-19 18:17
4,1,121,2015-02-19 19:22
5,2,121,2015-02-19 19:25
8,0,121,2015-02-19 22:17
9,1,121,2015-02-19 22:22
10,2,121,2015-02-19 22:25
So what you want is the MAX(Id) of the type = 0 rows for each row that has type = 1, where the Id is less. You can join and group to get that:
select max(t0.Id) Id
from Emp_tbl t1
join Emp_tbl t0 on t0.type = 0 and t0.Id < t1.Id
where t1.type = 1
group by t1.Id
The rest is just putting it together:
select *
from Emp_tbl
where type <> 0
union all
select t.*
from Emp_tbl t
join (
select max(t0.Id) Id
from Emp_tbl t1
join Emp_tbl t0 on t0.type = 0 and t0.Id < t1.Id
where t1.type = 1
group by t1.Id
) t0 on t.Id = t0.Id
SQL Fiddle demo