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
Related
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';
Let's say I have a table with two (indexed) columns: document IDs and the words the document contains.
____________________
__docID__|__Word___|
1 | it |
1 | rains |
2 | this |
2 | is |
2 | cold |
3 | it |
3 | is |
3 | snowing |
So there are three documents represented in the table:
it rains, this is cold, it is snowing
How I can get the table efficiently that contains all the rows of those documents that contain a certain word, let's say Word = 'it':
____________________
__docID__|__Word___|
1 | it |
1 | rains |
3 | it |
3 | is |
3 | snowing |
Can the query be something like:
SELECT * FROM table
WHERE (docID = this.docID, Word = 'it') is in table
You can use this.
select
*
from
`some_table`
where `docID` in (select `docID` from `some_table` where `Word` = 'it');
I have table of orders. Each customer (identified by the email field) has his own orders. I need to give a different sequence of order numbers for each customer. Here is example:
----------------------------
| email | number |
----------------------------
| test#com.com | 1 |
----------------------------
| example#com.com | 1 |
----------------------------
| test#com.com | 2 |
----------------------------
| test#com.com | 3 |
----------------------------
| client#aaa.com | 1 |
----------------------------
| example#com.com | 2 |
----------------------------
Is possible to do that in a simple way with mysql?
If you want update data in this table after an insert, first of all you need a primary key, a simple auto-increment column does the job.
After that you can try to elaborate various script to fill the number column, but as you can see from other answer, they are not so "simple way".
I suggest to assign the order number in the insert statement, obtaining the order number with this "simpler" query.
select coalesce(max(`number`), 0)+1
from orders
where email='test1#test.com'
If you want do everything in a single insert (better for performance and to avoid concurrency problems)
insert into orders (email, `number`, other_field)
select email, coalesce(max(`number`), 0) + 1 as number, 'note...' as other_field
from orders where email = 'test1#test.com';
To be more confident about not assign at the same customer two orders with the same number, I strongly suggest to add an unique constraint to the columns (email,number)
create a column order_number
SELECT #i:=1000;
UPDATE yourTable SET order_number = #i:=#i+1;
This will keep incrementing the column value in order_number column and will start right after 1000, you can change the value or even you can even use the primary key as the order number since it is unique all the time
I think one more need column for this type of out put.
Example
+------+------+
| i | j |
+------+------+
| 1 | 11 |
| 1 | 12 |
| 1 | 13 |
| 2 | 21 |
| 2 | 22 |
| 2 | 23 |
| 3 | 31 |
| 3 | 32 |
| 3 | 33 |
| 4 | 14 |
+------+------+
You can get this result:
+------+------+------------+
| i | j | row_number |
+------+------+------------+
| 1 | 11 | 1 |
| 1 | 12 | 2 |
| 1 | 13 | 3 |
| 2 | 21 | 1 |
| 2 | 22 | 2 |
| 2 | 23 | 3 |
| 3 | 31 | 1 |
| 3 | 32 | 2 |
| 3 | 33 | 3 |
| 4 | 14 | 1 |
+------+------+------------+
By running this query, which doesn't need any variable defined:
SELECT a.i, a.j, count(*) as row_number FROM test a
JOIN test b ON a.i = b.i AND a.j >= b.j
GROUP BY a.i, a.j
Hope that helps!
You can add number using SELECT statement without adding any columns in table orders.
try this:
SELECT email,
(CASE email
WHEN #email
THEN #rownumber := #rownumber + 1
ELSE #rownumber := 1 AND #email:= email END) as number
FROM orders
JOIN (SELECT #rownumber:=0, #email:='') AS t
I have a table that has approximately 4 million records. I would like to make it have 240 million like so:
Add an additional column of type BIGINT,
Import 59 times the data I already have,
And for each 4 million group of records, have the additional column to have a different value
The value of the additional column would come from another table.
So I have these records (except that I have 4 millions of them and not just 3):
| id | value |
+----+-------+
| 1 | 123 |
| 2 | 456 |
| 3 | 789 |
And I want to achieve this (except that I want 60 copies and not just 3):
| id | value | data |
+----+-------+------+
| 1 | 123 | 1 |
| 2 | 456 | 1 |
| 3 | 789 | 1 |
| 4 | 123 | 2 |
| 5 | 456 | 2 |
| 6 | 789 | 2 |
| 7 | 123 | 3 |
| 8 | 456 | 3 |
| 9 | 789 | 3 |
I tried to export my data (using SELECT .. INTO OUTFILE ...), then re-import it (using LOAD DATA INFILE ...) but it is really painfully slow.
Is there a fast way to do this?
Thank you!
Sounds like you'd like to take the cartesian product of 2 tables and create a new table since you say The value of the additional column would come from another table? If so, something like this should work:
create table yourtable (id int, value int);
create table yournewtable (id int, value int, data int);
create table anothertable (data int);
insert into yourtable values (1, 123), (2, 456), (3, 789);
insert into anothertable values (1), (2), (3);
insert into yournewtable
select t.id, t.value, a.data
from yourtable t, anothertable a
SQL Fiddle Demo
Results:
ID VALUE DATA
1 123 1
2 456 1
3 789 1
1 123 2
2 456 2
3 789 2
1 123 3
2 456 3
3 789 3
Edit, Side Note -- it looks like your ID field in your new table is not suppose to keep repeating the same ids? If so, you can use an AUTO_INCREMENT field instead. However, this could mess up the original rows if they aren't sequential.
First, I would recommend that you create a new table. You can do this using a cross join:
create table WayBigTable as
select t.*, n
from table t cross join
(select 1 as n union all select 2 union all select 3 union all select 4 union all select 5 union all
. . .
select 60
) n;
I'm not sure why you would want a bigint for this column. If you really need that, you can cast to unsigned.
Hmm. You need a cross join of your table with a range. Something in a line of this:
INSERT INTO table (id,value,data) SELECT id, value from table
CROSS JOIN (SELECT 2 UNION SELECT 3 UNION ... SELECT 60) AS data;
Use this answer Generating a range of numbers in MySQL as reference on number range.
Here's one idea...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,value INT NOT NULL
);
INSERT INTO my_table VALUES
(1 ,123),
(2 ,456),
(3 ,789);
ALTER TABLE my_table ADD COLUMN data INT NOT NULL DEFAULT 1;
SELECT * FROM my_table;
+----+-------+------+
| id | value | data |
+----+-------+------+
| 1 | 123 | 1 |
| 2 | 456 | 1 |
| 3 | 789 | 1 |
+----+-------+------+
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
INSERT INTO my_table SELECT NULL,value,data+i2.i*10+i1.i+1 FROM my_table,ints i1,ints i2;
SELECT * FROM my_table;
+-----+-------+------+
| id | value | data |
+-----+-------+------+
| 1 | 123 | 1 |
| 2 | 456 | 1 |
| 3 | 789 | 1 |
| 4 | 123 | 2 |
| 5 | 456 | 2 |
| 6 | 789 | 2 |
| 7 | 123 | 3 |
| 8 | 456 | 3 |
...
...
| 296 | 456 | 97 |
| 297 | 789 | 97 |
| 298 | 123 | 98 |
| 299 | 456 | 98 |
| 300 | 789 | 98 |
| 301 | 123 | 99 |
| 302 | 456 | 99 |
| 303 | 789 | 99 |
+-----+-------+------+
303 rows in set (0.00 sec)
Note, for 240 million rows, this is still going to be a bit slow :-(
Let's say we have the table like
id | group_id | TEXT |
--------------------------------------
1 | | NBA
--------------------------------------
2 | | NHL
--------------------------------------
3 | | NBA
--------------------------------------
4 | | NHL
--------------------------------------
5 | | NHL
--------------------------------------
Is it possible to create group_id with a MySQL function or query or anything :) using the fact of repeating (duplicate) text in the column TEXT ? to have a table like that
id | group_id | TEXT |
--------------------------------------
1 | 10 | NBA
--------------------------------------
2 | 11 | NHL
--------------------------------------
3 | 10 | NBA
--------------------------------------
4 | 11 | NHL
--------------------------------------
5 | 11 | NHL
--------------------------------------
You could try to use HEX function:
SELECT id, HEX(Text) as group_id, Text
FROM Tbl
If you want decimal value, you can conver it from hex:
SELECT id, CONV(HEX(Text), 16, 10) as group_id, Text
FROM Tbl
Result:
ID GROUP_ID TEXT
1 5128769 NBA
2 5128769 NBA
3 5130316 NHL
4 5130312 NHH
5 5130316 NHL
8 4342081 BAA
9 4342081 BAA
SQLFiddle
CREATE TEMPORARY TABLE nums (n int AUTO_INCREMENT PRIMARY KEY, txt varchar(4)) AUTO_INCREMENT=10;
INSERT INTO nums (txt) SELECT DISTINCT text FROM table1;
UPDATE table1 INNER JOIN nums ON txt=text SET group_id=n
SQLfiddle
Looking at my old answer I just thought of another way to solve the problem without a tmp table:
CREATE Table tbl (id int,grpid int, text varchar(10));
INSERT INTO tbl (id,text) VALUES (1,'NBA'),(2,'NBA'),
(3,'NHL'),(4,'NHH'),(5,'NHL'),(8,'BAA'),(9,'BAA');
SET #i:=100; -- set the start sequence number for grpid
UPDATE tbl INNER JOIN (
SELECT #i:=#i+1 gid,text FROM (
SELECT DISTINCT text FROM tbl ORDER BY text ) dt ) gi
ON tbl.text=gi.text
SET tbl.grpid=gi.gid;
tbl after the UPDATE:
| ID | GRPID | TEXT |
---------------------
| 1 | 102 | NBA |
| 2 | 102 | NBA |
| 3 | 104 | NHL |
| 4 | 103 | NHH |
| 5 | 104 | NHL |
| 8 | 101 | BAA |
| 9 | 101 | BAA |
sqlfiddle