Multiple row creation with one insert query in mysql - mysql

I want to insert multiple row using one insert query.
My table looks like below:
+---------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| seq_no | varchar(20) | YES | | NULL | |
| classname | varchar(20) | YES | | NULL | |
| classteacher | varchar(20) | YES | | NULL | |
| no_of_student | varchar(20) | YES | | NULL | |
| student_roll | varchar(20) | YES | | NULL | |
+---------------+-------------+------+-----+---------+-------+
Now I want to insert values in such a way that the table looks like below:
+--------+-----------+--------------+---------------+--------------+
| seq_no | classname | classteacher | no_of_student | student_roll |
+--------+-----------+--------------+---------------+--------------+
| 1 | physics | a | 02 | 01 |
| 1 | physics | a | 02 | 02 |
+--------+-----------+--------------+---------------+--------------+
where user doesn't have to put 'student_roll'.
Help me to find a way where using below kind of query one can get the above table:
insert into temp2(seq_no,classname,classteacher,no_of_student) values ('1','physics','a','02');
Here if no_of_student is 02 then row will be created with student_roll 01 and 02 sequentially.
I was thinking of this using for loop.

Solutions would typically include a table of numbers and insert ... select syntax.
Here is a simple solution using an explicit inline table:
insert into temp2(seq_no,classname,classteacher,no_of_student)
select 1, 'physics', 'a', 2, n
from (
select 1 n
union all select 2
union all select 3
union all select 4
union all select 5
union all select 6
union all select 7
union all select 8
union all select 9
union all select 10
) t
In MySQL 8.0, if you have a table with enough records, say other_table, you can use row_number():
insert into temp2(seq_no,classname,classteacher,no_of_student)
select 1, 'physics', 'a', 2, n
from (select row_number() over(order by rand()) n from other_table) t
where n <= :number_of_records to insert
Note: it has been commented already by RiggsFolly that the numeric-like values should be stored as numbers, not as strings. This answer assumes that. Else, you would need to cast() integer values to char, like so:
insert into ...
select '1', 'physics', 'a', '2', cast(n as char)
from ...

Here I have created another table named "other_table". It hold two columns "num" and "num_explain". and the table looks like below:
+-----+-------------+
| num | num_explain |
+-----+-------------+
| 02 | 01 |
| 02 | 02 |
+-----+-------------+
Then I have used the below code to get desired result:
insert into temp2(seq_no,classname,classteacher,no_of_student,student_roll) select '1','physics','a',num,num_explain from other_table where num='02';

Related

MariaDB Select Distinct ON (An Expression was Expected (Near ON)

I am trying to do a simple query using Distinct On a Column (As i still want to return all other columns in the table)
But when i attempt to use the ON (Column) clause it keeps displaying an error
"An Expression was expected (Near ON)"
I have no idea what this message means, as the query appears to be formatted correctly, is this something specific with MariaDB instead of MySQL?
MariaDB version 10.3.28 If this is of any use?
SELECT DISTINCT ON (No, Branch) *
FROM Table1
ORDER BY No, a DESC;
Table1
| ID | No | Branch | Datetime |
| --------- | ---------- | ------------- | ---------------- |
| 1 | 1 | 1 | 18/10/2021 10:00 |
| 2 | 1 | 1 | 19/10/2021 10:00 |
| 3 | 1 | 2 | 22/10/2021 10:00 |
| 4 | 1 | 2 | 20/10/2021 11:37 |
| 5 | 1 | 1 | 21/10/2021 10:00 |
| 6 | 1 | 1 | 22/10/2021 11:37 |
| 7 | 2 | 1 | 20/10/2021 10:00 |
| 8 | 2 | 1 | 22/10/2021 11:37 |
Basically i was wanting to use Distinct on "No" and "Branch" to essentially give me 1 record where No and Branch are unique and its using the MAX(Datetime)
I have attempted to use Group by clause, but this gives me a row with mixed results from other rows.
The results i am after would be:
| ID | No | Branch | Datetime |
| --------- | ---------- | ------------- | ---------------- |
| 6 | 1 | 1 | 22/10/2021 11:37 |
| 3 | 1 | 2 | 22/10/2021 10:00 |
| 8 | 2 | 1 | 22/10/2021 11:37 |
I would be wanting to to display all columns in the table, as i will also be doing a Join to fetch the Name based on No and Branch
Try:
CREATE TABLE table_tst (
`ID` int(5),
`No` int(5),
`Branch` int(5),
`Datetime` Datetime
);
INSERT INTO table_tst VALUES
(1,1,1,'2021-10-18 10:00:00'),
(2,1,1,'2021-10-19 10:00:00'),
(3,1,2,'2021-10-22 10:00:00'),
(4,1,2,'2021-10-20 11:37:00'),
(5,1,1,'2021-10-21 10:00:00'),
(6,1,1,'2021-10-22 11:37:00'),
(7,2,1,'2021-10-20 10:00:00'),
(8,2,1,'2021-10-22 11:37:00');
select *
from table_tst where (No,Branch,Datetime) in
(
select `No`,`Branch`,MAX(`Datetime`) as max_time
from table_tst
group by `No`,`Branch`
)
order by No ,Branch ASC;
Demo: https://www.db-fiddle.com/f/vhqJXYFy52xRtVBc97R1EL/8
datetime is a reserved word in mysql : https://dev.mysql.com/doc/refman/8.0/en/keywords.html and it should be in backticks or I suggest using other non reserved words

MySQL how to use a column with "-" in its name?

I am using MySQL for Windows 7. I have a column which has a "-" (minus) in its name. Somehow I can not run the following command:
INSERT INTO table (..., var-name, ...) VALUES(..., value, ...);
Can somebody please help me how I can execute this command?
Using
INSERT INTO table (..., [var-name], ...) VALUES(..., value, ...);
did not work
You have to wrap the name with backticks (`) like this:
INSERT INTO table (..., `var-name`, ...) VALUES(..., value, ...);
In order to escape the dash caracter.
MySQL escape character for column names is not [, it's `
So you need to use:
INSERT INTO table (..., `var-name`, ...) VALUES(..., value, ...);
An accident waiting to happen...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table (plusses INT NOT NULL, minuses INT NOT NULL, `plusses-minuses` INT NOT NULL);
INSERT INTO my_table VALUES
(10,2,6),
(12,6,6),
(13,9,6),
(14,12,6),
(15,2,6);
SELECT * FROM my_table;
+---------+---------+-----------------+
| plusses | minuses | plusses-minuses |
+---------+---------+-----------------+
| 10 | 2 | 6 |
| 12 | 6 | 6 |
| 13 | 9 | 6 |
| 14 | 12 | 6 |
| 15 | 2 | 6 |
+---------+---------+-----------------+
SELECT plusses, minuses, plusses-minuses FROM my_table;
+---------+---------+-----------------+
| plusses | minuses | plusses-minuses |
+---------+---------+-----------------+
| 10 | 2 | 8 |
| 12 | 6 | 6 |
| 13 | 9 | 4 |
| 14 | 12 | 2 |
| 15 | 2 | 13 |
+---------+---------+-----------------+

How can I do in MySQL an Insert with Select only if there is a value in the selected column?

I'm using MySQL and I have this kind of table:
table: historic_v1
id | student_id | level1_start_date | level1_score | level2_start_date | level2_score
1 | 2345 | 2016-02-10 | 7.5 | 2016-04-15 | 5
2 | 5634 | 2016-03-05 | NULL | NULL | NULL
3 | 4885 | 2015-12-02 | 6 | 2016-01-05 | NULL
I want to do an Insert in table historic_v2 with a Select in historic_v1, but I only want to have a row in historic_v2 if the value of the selected field in historic_v1 is not NULL.
I mean, the historic_v2 table needs to be like this:
table: historic_v2
id | student_id | level | key | date | score
1 | 2345 | 1 | start date | 2016-02-10 | NULL
2 | 2345 | 1 | score | NULL | 7.5
3 | 2345 | 2 | start date | 2016-04-15 | NULL
4 | 2345 | 2 | score | NULL | 5
5 | 5634 | 1 | start date | 2016-03-05 | NULL
6 | 4885 | 1 | start_date | 2015-12-02 | NULL
7 | 4885 | 1 | score | NULL | 6
8 | 4885 | 2 | start_date | 2016-01-05 | NULL
In this example, the student 2345 will have 4 rows in the historic_v2 table, the student 5634 only 1 row and the student 4885 3 rows.
How can I do this Insert with Select?
P.S.: I know that this structure is not nice, but it's just a small example of what I really need to do, and the solution of this problem will help me a lot.
Thanks in advance!
You can use a select union
insert into historic_v2 (student_id, level, key , date , score)
select student_id, 1, 'start date', level1_start_date, null
from historic_v2
where level1_start_date is not null
union
select student_id, 1, 'score', null, level1_score
from historic_v2
where level1_score is not null
union
select student_id, 2, 'start date', level2_start_date, null
from historic_v2
where level2_start_date is not null
union
select student_id, 2, 'score', null, level2_score
from historic_v2
where level2_score is not null
Similar thread: INSERT with SELECT
You can work off something like this..
INSERT INTO historic_v2 (...)
SELECT ...
FROM historic_v1
WHERE ...

Custom ordering SQL

I want to order things in the order 1, 1a, 1b, 2, 2a, 2b, ... on a lot of places. I am considering the following options:
1: use an enum field for 1, 1a, 1b, 2, 2a, 2b, ... such that it will order nicely. Downside defining on different places an enum like that.
2: create an extra table with two fields. A string field with the values 1, 1a, 1b, 2, 2a, 2b, ... and an order index and union with that table everywhere that ordering is needed. Downside is lots of unions.
What options would you advise, or do you consider other options?
Thanks
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,string VARCHAR(12) NOT NULL);
INSERT INTO my_table (string) VALUES ('2b'),('1'),('2a'),('1b'),('1a'),('11');
SELECT * FROM my_table;
+----+--------+
| id | string |
+----+--------+
| 1 | 2b |
| 2 | 1 |
| 3 | 2a |
| 4 | 1b |
| 5 | 1a |
| 6 | 11 |
+----+--------+
SELECT * FROM my_table ORDER BY string + 0,string;
+----+--------+
| id | string |
+----+--------+
| 2 | 1 |
| 5 | 1a |
| 4 | 1b |
| 3 | 2a |
| 1 | 2b |
| 6 | 11 |
+----+--------+
Try sorting using the below code :
SELECT * FROM t ORDER BY st REGEXP '^[[:alpha:]].*', st+0, st ;
Hope this helps

MYSQL - How to let 3 row data become 1 row data

Now I union 3 table and select become below show.
|remark|totalA|totalB|tatalC|
-----------------------------
| a | 123 | NULL | NULL |
| a | NULL | 123 | NULL |
| a | NULL | NULL | 123 |
How to let it become 1 row as below show?
|remark|totalA|totalB|tatalC|
-----------------------------
| a | 123 | 123 | 123 |
I trying group and distinct it but it show below
|remark|totalA|totalB|tatalC|
-----------------------------
| a | 123 | NULL | NULL |
select
remark,
sum(totalA) as totalA,
sum(totalB) as totalB,
sum(totalC) as totalC
from the_table
group by remark
Usesum along with group by as
select remark, sum(totalA), sum(totalB), sum(totalC)
from table_name
group by remark
Use an aggregate function, like MIN(), which will exclude nulls by default:
SELECT remark, MIN(totalA), MIN(totalB), MIN(totalC)
FROM Remarks
GROUP BY remark