I have a table with various null fields.
ID Value
1 A
2
3
4 B
5
Need to transform it to this output table:
ID Value
1 A
2 A
3 A
4 B
5 B
Requirement:
Preview the table before updating. Hence, a select statement with returns the above mentioned output table.
An update query which updates the first table to second table.
Unable to find any select query which shows the table in required format. Any help will be appreciated. Thanks.
A mysql query that uses a variable to keep track of the most recent non-null value
SELECT t1.id,
(CASE WHEN Value IS NULL
THEN #prevValue
ELSE #prevValue := Value END) Value
FROM myValues t1
CROSS JOIN (SELECT #prevValue := NULL) t2
ORDER BY t1.id
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,value CHAR(1) NULL
);
INSERT INTO my_table VALUES
(1,'A'),
(2,NULL),
(3,NULL),
(4,'B'),
(5,NULL);
SELECT x.*
, MAX(y.value)
FROM my_table x
JOIN my_table y
ON y.value IS NOT NULL
AND y.id <= x.id
GROUP
BY x.id;
+----+-------+--------------+
| id | value | MAX(y.value) |
+----+-------+--------------+
| 1 | A | A |
| 2 | NULL | A |
| 3 | NULL | A |
| 4 | B | B |
| 5 | NULL | B |
+----+-------+--------------+
IF OBJECT_ID(N'tempdb..#Increment')>0
BEGIN
DROP TABLE #Increment
END
CREATE TABLE #Increment (
id INT
, Increment VARCHAR(10)
)
INSERT INTO #Increment (id, Increment)
SELECT 1, 'A' UNION
SELECT 2, NULL UNION
SELECT 3, NULL UNION
SELECT 4, 'B' UNION
SELECT 5, NULL UNION
SELECT 6, NULL UNION
SELECT 7, 'C' UNION
SELECT 8, NULL UNION
SELECT 9, NULL
;WITH cte
AS (SELECT T1.id,
Increment = COALESCE(T1.Increment, (SELECT TOP 1 T2.Increment
FROM #Increment T2
WHERE T2.id < T1.id
AND T2.Increment IS NOT NULL
ORDER BY id DESC))
FROM #Increment T1)
UPDATE T
SET T.Increment = C.Increment
FROM #Increment T
INNER JOIN cte C
ON T.id = C.id
WHERE T.Increment IS NULL
select * from #Increment
Related
for an mass edit function I need to load the parents of multiple objects.
Doing this with single querys would kill the db. I'm using MySQL 5.7 My table is build like this:
CREATE TABLE `testtable` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`content` text,
`parentid` bigint(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8
INSERT INTO testtable(`id`, `content`, `parentid`)
VALUES(1, 'parentA1', 0),(5, 'parentA2', 1),(3, 'childA', 2),
(4, 'parentB', 0),(5, 'childB', 4);
For single object querys I use this statement to get all parents:
SELECT t.id, t.content, #pid := t.parentid AS parentid
FROM (SELECT * FROM Table1 order by id DESC) t
JOIN (SELECT #pid := 3) tmp
WHERE t.id = #pid
But I have absolutly no clue how this could work for multiple object at once without using union.
My whised ouput should look like this:
id | content | parentid | searchingChildID
1 | parentA1| 0 | 3
2 | parentA2| 1 | 3
3 | childA | 2 | 3
4 | parentB | 0 | 5
5 | childB | 4 | 5
Thanks in advance!
If you are running MySQL 8.0, this is a typical use case for a recursive query. Say you want all parents of objects 3 and 4, you can do:
with recursive cte as (
select t.id as originalid, t.* from table1 where id in (3, 4)
union all
select c.originalid, t.*
from cte c
inner join table1 t on t.id = c.parentid
)
select * from cte
for an mass edit function I need to load the parents of multiple objects.
For this operation, I would expect:
id | content | parentid | ultimateparent
1 | parentA1| 0 | 0
2 | parentA2| 1 | 0
3 | childA | 2 | 0
4 | parentB | 0 | 0
5 | childB | 4 | 0
Because 0 is the ultimate parent of all the rows. If you know the maximum depth, you can use left joins in pre-8 versions of MySQL:
select t1.*, coalesce(t3.parentid, t2.parentid, t1.parentid) as ultimateparent
from testtable t1 left join
testtable t2
on t2.id = t1.parentid left join
testtable t3
on t3.id = t2.parentid
You can trivially extend this with more left joins to handle deeper levels of parentage.
If 0 really means "no parent" (which is an odd choice when NULL is available) then you would seem to want:
id | content | parentid | ultimateparent
1 | parentA1| 0 | 1
2 | parentA2| 1 | 1
3 | childA | 2 | 1
4 | parentB | 0 | 4
5 | childB | 4 | 4
Then you can actually just tweak the above query to:
select t1.*, coalesce(t3.id, t2.id, t1.id) as ultimateparent
from testtable t1 left join
testtable t2
on t2.id = t1.parentid left join
testtable t3
on t3.id = t2.parentid;
Here is a db<>fiddle.
You can get the maximum child for each parent as well (although that seems quite arbitrary). In pre-8.0 versions of MySQL, variables are the simplest approach:
select t1.*,
(#max_child := if(#up = ultimateparent, #max_child,
if(#up := ultimateparent, id, id)
)
) as max_childid
from (select t1.*, coalesce(t3.id, t2.id, t1.id) as ultimateparent
from testtable t1 left join
testtable t2
on t2.id = t1.parentid left join
testtable t3
on t3.id = t2.parentid
order by ultimateparent, id desc
) t1 cross join
(select #up := -1, #max_child := -1) params;
I have two SQL Queries:
1. Get the the next row a row of where its status is "Active", Set it also to 'Active'
2. Remove the status of the previous row from the first sql query. Meaning, I want to remove the status of current row, move it to the next.
Code
UPDATE x AS a
INNER JOIN (
SELECT id, count(*) FROM x WHERE id=(select min(id) FROM ref_school_year where id > (SELECT ID FROM x WHERE status='START'))
) AS b on a.id = b.id
SET a.status = 'START'
WHERE a.id > 0
Second sql query
UPDATE ref_school_year as a
INNER JOIN(
SELECT * FROM ref_school_year
WHERE status='START'
ORDER BY id LIMIT 1
) as b on b.id = a.id
SET a.status=null
WHERE a.id > 0
Ex.
Before Query:
-----------------------------
| Rows | Status |
-----------------------------
| 1 | Active |
| 2 | null |
After Queries:
-----------------------------
| Rows | Status |
-----------------------------
| 1 | null |
| 2 | Active |
create table test (id int, status varchar(10));
insert test(id, status) values(1, 'Active'), (2, NULL);
update test t inner join (select id from test where status = 'Active' or exists (...)) t1 on t.id = t1.id set t.status = if(t.status = 'Active', NULL, 'Active');
The key for you is to use the IF function to update both at the same time. Hope I am right.
There are 5 columns X and A, B, C, D in table t. Columns A, B, C, D are varchar. and column X has to show us how many of the next row repeating characters. I need help to update column X.
Example :
|ID | X | A | B | C | D |
=========================
| 4 | 1 | 7 | J | 7 | Q |
| 3 | 2 | K | Q | 8 | 8 |
| 2 | 3 | 7 | 8 | 9 | J | next row X=3
| 1 | 0 | 7 | J | 8 | K | 0 default
ID-1 is the first and X is zero by default and from there begin calculations ID-2 and X=3 because we have ID-1 "7" "J" and "8" and the next row ID-2 have the combination "7 8 9 J" in ID-1 there "7 J 8 -" and X should be 3. Values of X can be between 0 and 4. ID-3, X=2 "- - 8 8" because in ID-2 have the combination "7 8 9 J" and i have 8 - twice in "K Q 8 8".
Added : 08/06
http://sqlfiddle.com/#!2/4586e/1
CREATE TABLE tmp
(
id int,
alnum CHAR(1),
cnt int,
PRIMARY KEY (id, alnum)
);
INSERT INTO tmp (id, alnum, cnt) SELECT id, A, 1 FROM tab ON DUPLICATE KEY UPDATE cnt = cnt + 1;
INSERT INTO tmp (id, alnum, cnt) SELECT id, B, 1 FROM tab ON DUPLICATE KEY UPDATE cnt = cnt + 1;
INSERT INTO tmp (id, alnum, cnt) SELECT id, C, 1 FROM tab ON DUPLICATE KEY UPDATE cnt = cnt + 1;
INSERT INTO tmp (id, alnum, cnt) SELECT id, D, 1 FROM tab ON DUPLICATE KEY UPDATE cnt = cnt + 1;
UPDATE tab INNER JOIN (
SELECT t1.id AS id, SUM(t2.cnt) AS sum
FROM tmp t1 INNER JOIN tmp t2 ON t1.id + 1 = t2.id
AND t1.alnum = t2.alnum
GROUP BY t1.id
) tmp3 ON tab.id = tmp3.id + 1
SET tab.X = tmp3.sum;
SELECT * FROM tab WHERE X > 4;
Original answer : 08/05
How about using tmp table which stores for each A, B, C, D columns into single rows. This makes us easy to calculate X value.
Below code assumes id is sequencial value. If not, please let me know there is another query for it.
CREATE TABLE tab
(
id INT,
X INT,
A CHAR(1),
B CHAR(1),
C CHAR(1),
D CHAR(1)
);
INSERT INTO tab VALUES (1, 0, '7', 'J', '8', 'K');
INSERT INTO tab VALUES (2, 0, '7', '8', '9', 'J');
INSERT INTO tab VALUES (3, 0, 'K', 'Q', '8', '8');
INSERT INTO tab VALUES (4, 0, '7', 'J', '7', 'Q');
CREATE TABLE tmp
(
id INT,
alnum CHAR(1)
);
INSERT INTO tmp SELECT id, A FROM tab;
INSERT INTO tmp SELECT id, B FROM tab;
INSERT INTO tmp SELECT id, C FROM tab;
INSERT INTO tmp SELECT id, D FROM tab;
UPDATE tab INNER JOIN (
SELECT t1.id AS id, COUNT(*) AS cnt
FROM tmp t1 INNER JOIN tmp t2 ON t1.id + 1 = t2.id
AND t1.alnum = t2.alnum
GROUP BY t1.id
) tmp3 ON tab.id = tmp3.id + 1
SET tab.X = tmp3.cnt;
mysql> SELECT * FROM tab ORDER BY id DESC;
+------+------+------+------+------+------+
| id | X | A | B | C | D |
+------+------+------+------+------+------+
| 4 | 1 | 7 | J | 7 | Q |
| 3 | 2 | K | Q | 8 | 8 |
| 2 | 3 | 7 | 8 | 9 | J |
| 1 | 0 | 7 | J | 8 | K |
+------+------+------+------+------+------+
4 rows in set (0.00 sec)
The X values in your example are from the "next" row, not the previous. Assuming you have an auto-incrementing id, you can calculate this information by looking at the next row. You can generate a query to do the calculation:
select ((case when t1.A in (tnext.A, tnext.B, tnext.C, tnext.D) then 1 else 0 end) +
(case when t1.B in (tnext.A, tnext.B, tnext.C, tnext.D) then 1 else 0 end) +
(case when t1.C in (tnext.A, tnext.B, tnext.C, tnext.D) then 1 else 0 end) +
(case when t1.D in (tnext.A, tnext.B, tnext.C, tnext.D) then 1 else 0 end)
) as X, t1.*
from (select t.*, (select max(id) from table t2 where t2.id > t.id) as nextid
from table t
) t1 left outer join
t tnext
on tnext.id = t1.nextid;
Depending on the database you are using, this code can be simplified and expressed differently. Also, the specific update syntax might depend on the database.
I have duplicate results like below where some column may have data and may not
| contact_info | icon | id | title | lastmodified_by |
+--------------+------+-----+---------------+------------------+
| 169 | 305 | 123 | Whakarewarewa | 2011100400305262 |
| NULL | NULL | 850 | Whakarewarewa | NULL |
+--------------+------+-----+---------------+----------------
| contact_info | icon | id | title | lastmodified_by |
+--------------+------+-----+---------------+------------------+
| NULL | NULL | 123 | Paris | NULL |
| NULL | NULL | 850 | Paris | NULL |
+--------------+------+-----+---------------+----------------
I want to delete record having less Data and if the all the Field values are exact same then delete any row.
There are thousand records like this.
Try this two-step solution:
Run this query to vew all duplicates - record having less Data -
SELECT t1.* FROM table t1
JOIN (
SELECT
title,
MIN(IF(contact_info IS NULL, 0, 1) + IF(contact_info IS NULL, 0, 1) + IF(lastmodified_by IS NULL, 0, 1)) min_value_data,
MAX(IF(contact_info IS NULL, 0, 1) + IF(contact_info IS NULL, 0, 1) + IF(lastmodified_by IS NULL, 0, 1)) max_value_data
FROM table GROUP BY title HAVING min_value_data <> max_value_data
) t2
ON t1.title = t2.title AND IF(t1.contact_info IS NULL, 0, 1) + IF(t1.contact_info IS NULL, 0, 1) + IF(t1.lastmodified_by IS NULL, 0, 1) <> t2.max_value_data
Rewrite it to DELETE statement and execute.
Then run this query to remove all duplicates except min ID:
DELETE t1 FROM table t1
JOIN (SELECT MIN(id) id, title FROM table GROUP BY title) t2
ON t1.id <> t2.id AND t1.title = t2.title;
Use this to select duplicates, feel free to alter this to a delete statement:
SELECT * FROM `test`,
(SELECT title, count( title ) AS ttl
FROM `test`
GROUP BY title
HAVING ttl >1) AS sub
WHERE test.title = sub.title
AND contact_info IS NULL AND lastmodified_by IS NULL
Main table = tes1
Create temp
CREATE TEMPORARY TABLE my_temp ( id INT(20) NOT NULL ) ENGINE=MEMORY;
Fill with id's to remove
INSERT INTO my_temp (id) SELECT id FROM tes1 AS main, ( SELECT title, count( title ) AS ttl FROM tes1 GROUP BY
title HAVING ttl >1 ) AS sub WHERE main.title = sub.title AND
main.contact_info IS NULL AND main.lastmodified_by IS NULL GROUP BY
main.contact_info, main.icon, main.title, main.lastmodified_by;
Delete!
DELETE FROM tes1 WHERE id IN (select id from my_temp);
Cleanup, note: do we really need this?
DROP TABLE my_temp;
I want to know is it possible to do if I have 4 number as below
1,2,3,4
In my data base have data exists as below
1,2,3,5,6,7
How can I query database and return 4 in 1 query
Please advise
CREATE TABLE `example` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
INSERT INTO example VALUES (1),(2),(3),(5),(6),(7);
SELECT t2.id FROM example AS t1
RIGHT JOIN (
SELECT 1 AS id UNION
SELECT 2 AS id UNION
SELECT 3 AS id UNION
SELECT 4 AS id
) AS t2
ON t1.id = t2.id
WHERE t1.id IS NULL;
+----+
| id |
+----+
| 4 |
+----+
Or use a temporary table:
CREATE TEMPORARY TABLE `tmp` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB;
INSERT INTO tmp VALUES (4);
SELECT t2.id FROM example AS t1
RIGHT JOIN tmp AS t2
ON t1.id = t2.id
WHERE t1.id IS NULL;
To see what's happening, switch things around a bit:
SELECT t1.id, t2.id FROM example AS t1
RIGHT JOIN (
SELECT 1 AS id UNION
SELECT 2 AS id UNION
SELECT 3 AS id UNION
SELECT 4 AS id
) AS t2
ON t1.id = t2.id;
+------+----+
| id | id |
+------+----+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| NULL | 4 |
+------+----+
SELECT id FROM
( SELECT 1 AS id UNION
SELECT 2 UNION
SELECT 3 UNION
SELECT 4
) AS TBL1
WHERE id NOT IN (SELECT id FROM thetable)