I want to insert data from table AnswerSets
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| Id | int(11) | YES | | NULL | |
| Q1 | int(11) | YES | | NULL | |
| Q2 | int(11) | YES | | NULL | |
| Q3 | int(11) | YES | | NULL | |
[...]
+-------+---------+------+-----+---------+-------+
to T_ANSWER_SET.
+--------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------+------+-----+---------+-------+
| U_ID | int(11) | YES | | NULL | |
| Q_ID | int(11) | YES | | NULL | |
| ANSWER | int(11) | YES | | NULL | |
+--------+---------+------+-----+---------+-------+
Therefor I use the following query in a loop in a procedure:
INSERT INTO T_ANSWER_SET (U_ID, Q_ID, ANSWER)
SELECT i, j, (SELECT c FROM AnswerSets WHERE Id = i);
i, j are integers and are used are incremented in a loop. c is a name of a column (like 'Q10') of AnswerSets from which I want the data. But I get always this:
+------+------+--------+
| U_ID | Q_ID | ANSWER |
+------+------+--------+
| 1 | 1 | 0 |
| 1 | 2 | 0 |
| 1 | 3 | 0 |
[...]
+------+------+--------+
What I want the query to do for i =3, j = 10 and c = 'Q10':
INSERT INTO T_ANSWER_SET (U_ID, Q_ID, ANSWER)
SELECT 3, 10, (SELECT Q10 FROM AnswerSets WHERE Id = 3);
Thanks in advance for your help.
Try PREPARE Statement:
MariaDB [(none)]> SET #`i` := 3,
-> #`j` := 1,
-> #`c` := '`Q10`';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> SET #`stmt` := CONCAT('
'> INSERT INTO `T_ANSWER_SET` (`U_ID`, `Q_ID`, `ANSWER`)
'> SELECT ', #`i`, ', ', #`j`, ', (SELECT ', #`c`, '
'> FROM `AnswerSets`
'> WHERE `Id` = ', #`i`, ')
'> ');
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> SELECT #`stmt`;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| #`stmt` |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
INSERT INTO `T_ANSWER_SET` (`U_ID`, `Q_ID`, `ANSWER`)
SELECT 3, 1, (SELECT `Q10`
FROM `AnswerSets`
WHERE `Id` = 3)
|
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
MariaDB [(none)]> -- PREPARE `stmt` FROM #`stmt`;
MariaDB [(none)]> -- EXECUTE `stmt`;
MariaDB [(none)]> -- DEALLOCATE PREPARE `stmt`;
Related
I am trying to remove a column from a MySQL table that I am using with Handsontable. When I remove a column from the Handsontable, I can get the column's index using the afterRemoveCol() callback:
afterRemoveCol: function (index, amount) {
alert(index +' amount: '+amount);
}
I would like to remove the column using the column number (n) returned by this callback function from the MySQL table using something like:
ALTER TABLE tbl_Blah DROP COLUMN n;
So, if I want to drop column #3 from the MySQL table, How would I do this using just the column number?
To add to RMathis answer, you can do everything within SQL by also using SET to define the DROP string in conjuntion with PREPARE and EXECUTE
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Table1
(`col1` varchar(1),
`col2` varchar(1),
`col3` varchar(1),
`col4` varchar(1),
`col5` varchar(1))
;
set #col = (select column_name
from information_schema.columns
where table_name='table1' and ordinal_position=3);
SET #s = CONCAT("alter table table1 drop column ", #col);
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Query 1:
desc table1
Results:
| COLUMN_NAME | COLUMN_TYPE | IS_NULLABLE | COLUMN_KEY | COLUMN_DEFAULT | EXTRA |
|-------------|-------------|-------------|------------|----------------|-------|
| col1 | varchar(1) | YES | | (null) | |
| col2 | varchar(1) | YES | | (null) | |
| col4 | varchar(1) | YES | | (null) | |
| col5 | varchar(1) | YES | | (null) | |
SQL from SQL can generate the drop statement using ordinal_position from information_schema.columns.
mysql test> create table test.tab (col1 char(1), col2 char(1), col3 char(1), col4 char(1), col5 char(1));
Query OK, 0 rows affected (0.01 sec)
mysql test> desc test.tab;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| col1 | char(1) | YES | | NULL | |
| col2 | char(1) | YES | | NULL | |
| col3 | char(1) | YES | | NULL | |
| col4 | char(1) | YES | | NULL | |
| col5 | char(1) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
5 rows in set (0.00 sec)
This query is generating the statement to drop the third column...
mysql test> select concat('alter table ',table_schema,'.',table_name,' drop column ',column_name,';') as query1 from information_schema.columns where table_schema='test' and table_name='tab' and ordinal_position=3;
+----------------------------------------+
| query1 |
+----------------------------------------+
| alter table test.tab drop column col3; |
+----------------------------------------+
1 row in set (0.00 sec)
Now to run the projected command...
mysql test> alter table test.tab drop column col3;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
The column definition has been removed from the table.
mysql test> desc test.tab;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| col1 | char(1) | YES | | NULL | |
| col2 | char(1) | YES | | NULL | |
| col4 | char(1) | YES | | NULL | |
| col5 | char(1) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
4 rows in set (0.01 sec)
Name them (columns in your db mirroring the spreadsheet) with the numbers/letters in full correspondence with your spreadsheet.
And then you'd be able to use regular ALTER TABLE ... DROP COLUMN.
I how defined a procedure in MySql which has an input and input will be a name of column that will be added to table 'test1' but sql names that column input instead of using the value of input .how can i do this in the right way?
DELIMITER
CREATE PROCEDURE p1
(IN input CHAR(20))
BEGIN
ALTER TABLE test1
ADD COLUMN input char(20);
END
DELIMITER ;
You should google dynamic sql and read the manual https://dev.mysql.com/doc/refman/8.0/en/sql-syntax-prepared-statements.html
In the meantime here's an example.
drop procedure if exists p;
alter table users
drop column abc;
DELIMITER $$
CREATE PROCEDURE p
(IN input CHAR(20))
BEGIN
#ALTER TABLE test1
#ADD COLUMN input char(20);
set #sql = concat('alter table users add column ',input,' char(20);');
select #sql;
prepare sqlstmt from #sql;
execute sqlstmt;
deallocate prepare sqlstmt;
END $$
DELIMITER ;
call p('abc');
describe users;
MariaDB [sandbox]> call p('abc');
+--------------------------------------------+
| #sql |
+--------------------------------------------+
| alter table users add column abc char(20); |
+--------------------------------------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.42 sec)
MariaDB [sandbox]> describe users;
+---------------------+-------------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+-------------+------+-----+-------------------+-------+
| id | int(11) | NO | PRI | NULL | |
| userName | varchar(60) | NO | | NULL | |
| photo | varchar(50) | YES | | NULL | |
| status | int(11) | YES | | NULL | |
| ts | datetime | YES | | CURRENT_TIMESTAMP | |
| events_participated | int(11) | YES | | NULL | |
| fb_uid | int(11) | YES | | NULL | |
| Column_name | varchar(10) | YES | | NULL | |
| post_type | varchar(10) | YES | | NULL | |
| password | varchar(8) | YES | | NULL | |
| abc | char(20) | YES | | NULL | |
+---------------------+-------------+------+-----+-------------------+-------+
11 rows in set (0.03 sec)
SQL:
DELIMITER $$ CREATE TRIGGER `Activation_code` BEFORE UPDATE
ON `user_users` FOR EACH ROW
BEGIN
IF OLD.activation_code_time < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 15 MINUTE)) THEN SET NEW.activation_code = SELECT(ROUND((RAND() * (999999-100000))+100000)), NEW.activation_code_time = SELECT(UNIX_TIMESTAMP());
END
$$ DELIMITER ;
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT(ROUND((RAND() * (999999-100000))+100000)), NEW.activation_code_time = SEL' at line 4
Can anyone please tell me where is an error. and How can I resolve it?
Selects need to be bracketed, all statements need to be terminated with ; and you need an end if
DELIMITER $$
CREATE TRIGGER `Activation_code` BEFORE UPDATE
ON `user_users` FOR EACH ROW
BEGIN
IF OLD.activation_code_time < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 15 MINUTE)) THEN
SET NEW.activation_code = (SELECT(ROUND((RAND() * (999999-100000))+100000))),
NEW.activation_code_time = (SELECT(UNIX_TIMESTAMP()));
END IF;
END $$
DELIMITER ;
If there is a chance that activation_code_time may be null you should code for it.
drop trigger if exists `Activation_code`;
DELIMITER $$
create TRIGGER `Activation_code` BEFORE UPDATE
ON `users` FOR EACH ROW
BEGIN
IF coalesce(OLD.activation_code_time,0) < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 MINUTE)) THEN
SET NEW.activation_code = (SELECT(ROUND((RAND() * (999999-100000))+100000))),
NEW.activation_code_time = (SELECT(UNIX_TIMESTAMP()));
END IF;
END
$$ DELIMITER ;
mysql> describe users;
+----------------------+-------------+------+-----+---------+-------------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+-------------+------+-----+---------+-------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
| uid | int(11) | YES | | NULL | |
| NAMID | varchar(20) | YES | | NULL | VIRTUAL GENERATED |
| activation_code | int(11) | YES | | NULL | |
| activation_code_time | int(11) | YES | | NULL | |
+----------------------+-------------+------+-----+---------+-------------------+
6 rows in set (0.00 sec)
mysql> select * from users;
+----+------+------+-------+-----------------+----------------------+
| id | name | uid | NAMID | activation_code | activation_code_time |
+----+------+------+-------+-----------------+----------------------+
| 1 | aaa | 1 | aaa|1 | 589392 | 1514804785 |
| 2 | bbb | 2 | bbb|2 | NULL | NULL |
+----+------+------+-------+-----------------+----------------------+
2 rows in set (0.00 sec)
mysql> select * from users;update users set name = 'aaa' where id = 1;select * from users;
+----+------+------+-------+-----------------+----------------------+
| id | name | uid | NAMID | activation_code | activation_code_time |
+----+------+------+-------+-----------------+----------------------+
| 1 | aaa | 1 | aaa|1 | 589392 | 1514804785 |
| 2 | bbb | 2 | bbb|2 | NULL | NULL |
+----+------+------+-------+-----------------+----------------------+
2 rows in set (0.00 sec)
Query OK, 1 row affected (0.05 sec)
Rows matched: 1 Changed: 1 Warnings: 0
+----+------+------+-------+-----------------+----------------------+
| id | name | uid | NAMID | activation_code | activation_code_time |
+----+------+------+-------+-----------------+----------------------+
| 1 | aaa | 1 | aaa|1 | 616615 | 1514805252 |
| 2 | bbb | 2 | bbb|2 | NULL | NULL |
+----+------+------+-------+-----------------+----------------------+
2 rows in set (0.00 sec)
I have a mysql table with a null-able int column named 'status', and I have two records in the table where one of the status is 2 when the other is NULL, but when I select the records with query 'status!=2', the record (status=null) is not shown.
mysql>
mysql>
mysql> desc admin_user;
+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| acct_name | varchar(32) | YES | | NULL | |
| password | varchar(32) | YES | | NULL | |
| user_name | varchar(32) | YES | | NULL | |
| description | varchar(128) | YES | | NULL | |
| status | int(11) | YES | | NULL | |
| role | int(11) | NO | | 1 | |
| create_date | date | YES | | NULL | |
| update_date | date | YES | | NULL | |
+-------------+------------------+------+-----+---------+----------------+
9 rows in set (0.00 sec)
mysql> select id, acct_name, status from admin_user;
+----+-----------+--------+
| id | acct_name | status |
+----+-----------+--------+
| 1 | letme | NULL |
| 3 | admin | 2 |
+----+-----------+--------+
2 rows in set (0.00 sec)
mysql> select id, acct_name, status from admin_user where status=2;
+----+-----------+--------+
| id | acct_name | status |
+----+-----------+--------+
| 3 | admin | 2 |
+----+-----------+--------+
1 row in set (0.00 sec)
mysql> select id, acct_name, status from admin_user where status IS NULL;
+----+-----------+--------+
| id | acct_name | status |
+----+-----------+--------+
| 1 | letme | NULL |
+----+-----------+--------+
1 row in set (0.00 sec)
mysql> select id, acct_name, status from admin_user where status!=2;
Empty set (0.00 sec)
mysql>
As you can see, the record whose status is NULL can not be selected using the query 'status!=2'. I also tried 'status<>2'. Can anybody help?
Nulls are really interesting.
The NULL value can be surprising until you get used to it.
Conceptually, NULL means “a missing unknown value” and it is treated
somewhat differently from other values.
What's more
You cannot use arithmetic comparison operators such as =, <, or <> to
test for NULL
There are lots of different ways to write this. One of them being:
select id, acct_name, status from admin_user where status IS NULL
OR status != 2
Alterantively as #shA.t suggested.
select id, acct_name, status from table1 where COALESCE(status, 0) != 2
Just check that 0 is indeed a number that doesn't appear any where else in the table.
I am having issues inserting Id fields from two tables into a single record in a third table.
mysql> describe ing_titles;
+----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+------------------+------+-----+---------+----------------+
| ID_Title | int(10) unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(64) | NO | UNI | NULL | |
+----------+------------------+------+-----+---------+----------------+
2 rows in set (0.22 sec)
mysql> describe ing_categories;
+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| ID_Category | int(10) unsigned | NO | PRI | NULL | auto_increment |
| category | varchar(64) | NO | UNI | NULL | |
+-------------+------------------+------+-----+---------+----------------+
2 rows in set (0.02 sec)
mysql> describe ing_title_categories;
+-------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+------------------+------+-----+---------+----------------+
| ID_Title_Category | int(10) unsigned | NO | PRI | NULL | auto_increment |
| ID_Title | int(10) unsigned | NO | MUL | NULL | |
| ID_Category | int(10) unsigned | NO | MUL | NULL | |
+-------------------+------------------+------+-----+---------+----------------+
3 rows in set (0.04 sec)
Let's say the data from the tables is:
mysql> select * from ing_titles;
+----------+-------------------+
| ID_Title | title |
+----------+-------------------+
| 3 | Chicken |
| 2 | corn |
| 1 | Fettucini Alfredo |
+----------+-------------------+
3 rows in set (0.00 sec)
mysql> select * from ing_categories;
+-------------+----------+
| ID_Category | category |
+-------------+----------+
| 1 | Dinner |
| 3 | Meat |
| 2 | Veggie |
+-------------+----------+
3 rows in set (0.00 sec)
I want to insert into ing_title_categories the record "corn, Veggie" or where ID_Title = 2 and ID_Category = 2.
Here's what I tried:
INSERT INTO ing_title_categories (ID_Title, ID_Category)
SELECT ing_titles.ID_Title, ing_categories.ID_Category
FROM ing_title_categories
LEFT JOIN ing_titles ON ing_title_categories.ID_Title=ing_titles.ID_Title
LEFT JOIN ing_categories ON ing_title_categories.ID_Category=ing_categories.ID_Category
WHERE (ing_titles.ID_Title=2) AND (ing_categories.ID_Category = 2);
There is no data inserted into the table ing_title_categories, and here is the reply from MySQL:
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
What is the correct syntax for inserting the ing_titles.ID_Title and ing_categories.ID_Category into the table ing_titles_categories?
Please, no PHP or Python examples. Use SQL that I can copy and paste into the MySQL prompt. I will be adding this to a C++ program, not PHP, JavaScript or Python.
Edit 1:
The ing_title_categories.ID_Title and ing_title_categories.ID_Category are foreign keys into the other tables.
INSERT INTO
ing_title_categories (ID_Title, ID_Category)
SELECT
ing_titles.ID_Title, ing_categories.ID_Category
FROM
ing_titles, ing_categories
WHERE
ing_titles.ID_Title = ing_categories.ID_Category AND
ing_titles.ID_Title = 2 AND ing_categories.ID_Category = 2;
SQL Fiddle demo
After taking advice from #DrewPierce and #KaiserM11, here is the MySQL sequence:
mysql> INSERT INTO ing_title_categories (ID_Title, ID_Category)
-> SELECT
-> ing_titles.ID_Title,
-> ing_categories.ID_Category
-> FROM ing_titles, ing_categories
-> where (ing_titles.ID_Title = 2) AND (ing_categories.ID_Category = 2)
-> ;
Query OK, 1 row affected (0.07 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from ing_title_categories;
+-------------------+----------+-------------+
| ID_Title_Category | ID_Title | ID_Category |
+-------------------+----------+-------------+
| 17 | 2 | 2 |
+-------------------+----------+-------------+
1 row in set (0.00 sec)
In this case, only possible way I see is using a UNION query like
INSERT INTO ing_title_categories (ID_Title, ID_Category)
SELECT Title, NULL
FROM ing_title WHERE ID_Title = 2
UNION
SELECT NULL, category
FROM ing_categories
WHERE ID_Category = 2
(OR)
You can change your table design and use an AFTER INSERT trigger to perform the same in one go.
EDIT:
If you can change your table design to something like below (No need of that extra chaining table)
ing_titles(ID_Title int not null auto_increment PK, title varchar(64) not null);
ing_categories( ID_Category int not null auto_increment PK,
category varchar(64) not null,
ing_titles_ID_Title int not null,
FOREIGN KEY (ing_titles_ID_Title)
REFERENCES ing_titles(ID_Title));
Then you can use a AFTER INSERT trigger and do the insertion like
DELIMITER //
CREATE TRIGGER ing_titles_after_insert
AFTER INSERT
ON ing_titles FOR EACH ROW
BEGIN
-- Insert record into ing_categories table
INSERT INTO ing_categories
( category,
ing_titles_ID_Title)
VALUES
('Meat' NEW.ID_Title);
END; //
DELIMITER ;