SQL statement to insert repetitive data - mysql

current situation is to add below value of A01, B03, Z11 and X21 in repetitive way in field code for 400 hundreds row of data in table BabyCode.
Above is current table - without value in 'Code" column
Above is to be updated table - repetitive value is added in 'Code' column

You can do this:
INSERT INTO BabyCode
SELECT Codes.Code
FROM
(
SELECT id
FROM
(
SELECT t3.digit * 100 + t2.digit * 10 + t1.digit + 1 AS id
FROM TEMP AS t1
CROSS JOIN TEMP AS t2
CROSS JOIN TEMP AS t3
) t
WHERE id <= 400
) t,
(
SELECT 1 AS ID, 'A01' AS Code
UNION ALL
SELECT 2, 'B03'
UNION ALL
SELECT 3, 'Z11'
UNION ALL
SELECT 4, 'X21'
) codes;
But you will need to define a temp table, to use as an anchor table:
CREATE TABLE TEMP (Digit int);
INSERT INTO Temp VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
SQL Fiddle Demo
This will insert 400 hundred rows of the values A01, B03, Z11, and X21, into the code column in the table BabyCode.

You could put the four values into a virtual table identical to that used in #Mahmoud Gamal's answer, and, if the ID values in your table start at 1 and are sequential (have neither gaps nor duplicates), you could use the following method to join to the virtual table and update the target's Code column:
UPDATE YourTable t
INNER JOIN (
SELECT 1 AS ID, 'A01' AS Code
UNION ALL SELECT 2, 'B03'
UNION ALL SELECT 3, 'Z11'
UNION ALL SELECT 4, 'X21'
) x
ON (t.ID - 1) MOD 4 + 1 = x.ID
SET t.Code = x.Code
;
Otherwise you could use variables to assign 1, 2, 3, 4 sequentially to every row of your table, then you would be able join to the virtual table using those values:
UPDATE YourTable t
INNER JOIN (
SELECT ID, #rnk := CASE WHEN #rnk = 4 THEN 0 ELSE #rnk END + 1 AS rnk
FROM YourTable
CROSS JOIN (SELECT #rnk := 0) x
ORDER BY ID
) r ON t.ID = r.ID
INNER JOIN (
SELECT 1 AS ID, 'A01' AS Code
UNION ALL SELECT 2, 'B03'
UNION ALL SELECT 3, 'Z11'
UNION ALL SELECT 4, 'X21'
) x
ON r.rnk = x.ID
SET t.Code = x.Code
;
Both queries can be played with at SQL Fiddle:
Method 1
Method 2

Related

Find all NULL values and set them to lowest unused number using MySQL query

I want to find all NULL values in column parameter_id and set them to lowest unused parameter_id.
I have query which will find lowest unused parameter_id, I also know how to get list of NULL values.
SELECT MIN(t1.parameter_id)+1 FROM table AS t1 WHERE NOT EXISTS (SELECT * FROM table AS t2 WHERE t2.parameter_id = t1.parameter_id+1)
I can get list of all rows with parameter_id=NULL, then make query to find current lowest unused parameter_id and then update parameter_id to that lowest unused number. Since table has 50.000 rows, this approach would create thousands of queries (50.000 * 2 per row).
Is there way to run "single query" which will find all parameter_id=NULL and update them all to current lowest unused parameter_id?
Here is table decrtiption (MySQL 5.5):
id (INT) primary key, auto_increment
parameter_id (INT) default NULL
Sample data:
# id, parameter_id
1, NULL
2, 1
3, NULL
4, 5
5, 3
Desired result:
# id, parameter_id
1, 2
2, 1
3, 4
4, 5
5, 3
EDIT:
I distilled what I want to single query. I simply need to run this query until there is 0 rows affected by UPDATE.
UPDATE `table`
SET parameter_id=
(SELECT *
FROM
(SELECT MIN(t1.parameter_id)+1
FROM `table` AS t1
WHERE NOT EXISTS
(SELECT *
FROM `table` AS t2
WHERE t2.parameter_id = t1.parameter_id+1)) AS t4)
WHERE parameter_id IS NULL LIMIT 1
The following enumerates the unused parameter ids:
select t.*, (#rn := #rn + 1) as seqnum
from table t cross join
(select #rn := 0) params
where not exists (select 1 from table t2 where t2.parameter_id = t.id)
order by t.id;
(You might want to put this in a temporary table with an index on seqnum for the subsequent query.)
The problem is getting a join key for the update. Here is a bit of a kludge: I'm going to add a column, enumerate it, and then drop it:
alter table `table` add column null_seqnum;
update `table` t cross join (select #rn1 := 0) params
set null_seqnum = (#rn1 := #rn1 + 1)
where parameter_id is null;
update `table` t join
(select t.*, (#rn := #rn + 1) as seqnum
from `table` t cross join
(select #rn := 0) params
where not exists (select 1 from `table` t2 where t2.parameter_id = t.id)
order by t.id
) tnull
on t.null_seqnum = tnull.seqnum
set t.parameter_id = tnull.id;
alter table `table` drop column null_seqnum;

SELECT Current and Previous row WHERE condition

id value
---------
1 a
2 b
3 c
4 a
5 t
6 y
7 a
I want to select all rows where the value is 'a' and the row before it
id value
---------
1 a
3 c
4 a
6 y
7 a
I looked into
but I want to get all such rows in one query.
Please help me start
Thank you
I think the easiest way might be to use variables:
select t.*
from (select t.*,
(rn := if(value = 'a', 1, #rn + 1) as rn
from table t cross join
(select #rn := 0) params
order by id desc
) t
where rn in (1, 2)
order by id;
An alternative method uses a correlated subquery to get the previous value and then uses this in the where clause:
select t.*
from (select t.*,
(select t2.value
from table t2
where t2.id < t.id
order by t2.id desc
limit 1
) as prev_value
from table t
) t
where value = 'a' or prev_value = 'a';
With an index on id, this might even be faster than the method using variables.

select every other row in MySQL without depending on any ID?

Considering following table that doesn't have any primary key, can I select every other row?
col1 col2
2 a
1 b
3 c
12 g
first select must find: 2, 3
second select must find: 1, 12
is that possible?
In unique MySQL fashion:
select *
from (
select *
, #rn := #rn + 1 as rn
from Table1
join (select #rn := 0) i
) s
where rn mod 2 = 0 -- Use = 1 for the other set
Example at SQL Fiddle.
Try this. I've adapted it from the answer linked below.
I tested it on SQLFiddle and it appears to work.
http://sqlfiddle.com/#!2/0bccf/28
http://sqlfiddle.com/#!2/0bccf/29
Odd Rows:
SELECT x.*
FROM (
SELECT #rownum:=#rownum+1 rownum, t.*
FROM (SELECT #rownum:=0) r, table t
) x
WHERE MOD(x.rownum, 2) = 1
Even Rows:
SELECT x.*
FROM (
SELECT #rownum:=#rownum+1 rownum, t.*
FROM (SELECT #rownum:=0) r, table t
) x
WHERE MOD(x.rownum, 2) = 0
Adapted from:
MySQL row number
yes possible using temp variable
Example :
set #a := 0;
select * from car_m_city WHERE mod((#a:=#a+1), 2) = 1
Explanation :
here in sql we declare #a( set #a := 0;) temp variable.(#a:=#a+1) now #a increment by 1.jsut like simple way to check odd or even
mod((#a:=#a+1), 2) = 1 for odd data
mod((#a:=#a+1), 2) = 0 for even data
This works for me.
SET #row_number = 0;
select* from (
SELECT
(#row_number:=#row_number + 1) AS num, col1,col2
FROM
TABLE1
) as t WHERE num%2=0
You can use mod 1 for odd or mod 0 for even rows
This should work for MySQL:
SELECT col1, col2
FROM (
SELECT col1, col2, #rowNumber:=#rowNumber+ 1 rn
FROM YourTable
JOIN (SELECT #rowNumber:= 0) r
) t
WHERE rn % 2 = 1
This uses % which is the MOD operator.
And here is the sample fiddle: http://sqlfiddle.com/#!2/cd31b/2

How to get the smallest Integers not yet in a database column

I have a table in a MySQL DB with an UNIQUE INT(10) column. The table is pretty populated and the row contains non-consecutive entries of Integer numbers in that column. I would like to do a query, which gets me the smallest number (or the n smallest numbers) that is not in any row.
Example: The table contains rows with values (1, 2, 3, 5, 7, 8, 10, 12, 15) for the column. The sql statement should return i.e. the five lowest non-contained values, which are 4, 6, 9, 11, 13 in this case.
Is this possible with MySQL?
You can use a "numbers" table (it's handy for various operations):
CREATE TABLE num
( i UNSIGNED INT NOT NULL
, PRIMARY KEY (i)
) ;
INSERT INTO num (i)
VALUES
(1), (2), ..., (1000000) ;
Then:
SELECT
num.i
FROM
num
LEFT JOIN
tableX AS t
ON num.i = t.columnX
WHERE
t.columnX IS NULL
ORDER BY
num.i
LIMIT 5
or:
SELECT
num.i
FROM
num
WHERE
NOT EXISTS
( SELECT *
FROM tableX AS t
WHERE num.i = t.columnX
)
ORDER BY
num.i
LIMIT 5
Another approach, without using an auxilary table, would be to use MySQL variables. You can test it in SQL-Fiddle, test-2. The output is not the same as the previous (just to show that it can be done):
SELECT start_id, end_id
FROM
( SELECT
IF( t.columnX <> #id, #id, NULL) AS start_id
, IF( t.columnX <> #id, t.columnX-1, NULL) AS end_id
, #rows := #rows + (t.columnX - #id) AS r
, #id := t.columnX + 1 AS running_id
FROM
tableX AS t
CROSS JOIN
( SELECT #rows := 0
, #id := 1
) AS dummy
WHERE
#rows < 5
ORDER BY
t.columnX
) AS tmp
WHERE
start_id IS NOT NULL
This will work, but I think it is pretty inefficient. You won't need an extra table though (a table that would be (2^31-1)*4/1024^3 = 8GB for all positive numbers in INT). Also I advise you look at why you need this, because it might not be neccesary.
Also it will return the start and end of a range, but not all numbers in that range. (e.g. if you have numbers 1 and 5 it will return {0,2,4,6})
SELECT (t.num-1) AS bound FROM t
WHERE t.num-1 NOT IN (SELECT t.num FROM t)
UNION
SELECT (t.num+1) AS bound FROM t
WHERE t.num+1 NOT IN (SELECT t.num FROM t)
As I said this will be pretty inefficient, JOINs might be faster but you would need benchmark it.
SELECT (t.num-1) AS bound FROM t
LEFT JOIN t AS u ON t.num-1 = u.num
WHERE u.num IS NULL
UNION
SELECT (t.num+1) AS bound FROM t
LEFT JOIN t AS u ON t.num+1 = u.num
WHERE u.num IS NULL

T-SQL for finding consecutive increasing values

Let's say I have the following very simple schema:
Create Table MyTable (
PrimaryKey int,
Column1 datetime.
Column2 int
)
I need a query that orders the data based on Column1, and finds the first 10 consecutive rows where the value of Column2 in the current row is greater than the value of column2 in the prior row.
Q is used to get a ranking value rn ordered by Column1. Added in PrimaryKey in case there are ties in Column1. C is a recursive CTE that loops from the top ordered by rn incrementing cc for each increasing value of Column2. It will break from the recursion when cc reaches 10. Finally get the last 10 rows from C. The where clause takes care of the case when there are no 10 consecutive increasing values.
with Q as
(
select PrimaryKey,
Column1,
Column2,
row_number() over(order by Column1, PrimaryKey) as rn
from MyTable
),
C as
(
select PrimaryKey,
Column1,
Column2,
rn,
1 as cc
from Q
where rn = 1
union all
select Q.PrimaryKey,
Q.Column1,
Q.Column2,
Q.rn,
case
when Q.Column2 > C.Column2 then C.cc + 1
else 1
end
from Q
inner join C
on Q.rn - 1 = C.rn
where C.cc < 10
)
select top 10 *
from C
where 10 in (select cc from C)
order by rn desc
option (maxrecursion 0)
Version 2
As Martin Smith pointed out in a comment, the above query has really bad performance. The culprit is the first CTE. The version below use table variable to hold the ranked rows. The primary key directive on rn creates an index that will be used in the join in the recursive part of the query. Apart from the table variable this does the same as above.
declare #T table
(
PrimaryKey int,
Column1 datetime,
Column2 int,
rn int primary key
);
insert into #T
select PrimaryKey,
Column1,
Column2,
row_number() over(order by Column1, PrimaryKey) as rn
from MyTable;
with C as
(
select PrimaryKey,
Column1,
Column2,
rn,
1 as cc
from #T
where rn = 1
union all
select T.PrimaryKey,
T.Column1,
T.Column2,
T.rn,
case
when T.Column2 > C.Column2 then C.cc + 1
else 1
end
from #T as T
inner join C
on T.rn = C.rn + 1
where C.cc < 10
)
select top 10 *
from C
where 10 in (select cc from C)
order by rn desc
option (maxrecursion 0)