I have table with data:
| id | status |
+-----+--------+
| 1 | 1 |
| 2 | 1 |
| 3 | 0 |
| 4 | 2 |
| 5 | 2 |
I have file, that I need to load into this table and replace:
| id | status |
+----+--------+
| 1 | 1 |
| 2 | 0 |
| 3 | 0 |
| 4 | 0 |
| 5 | 1 |
I have one condition: if status in table =2 and status in file =0, leave status in table =2, otherwise replace status in table from file.
After query I need to get new data:
| id | status |
+-----+--------+
| 1 | 1 |
| 2 | 0 |
| 3 | 0 |
| 4 | 2 |
| 5 | 1 |
I'm trying do it with query:
load data local
infile '".$file."'
replace
into table t1
fields terminated by ',' enclosed by '\"'
(#tid,
teacher_name,
email,
#pid,
tca_form_type,
prod_company,
prod_name,
#stts)
set status = if((select status from (select status from t1 where teacher_id=#tid and prod_id=#pid) as tmp)=2 and #stts=0,status,#stts),
teacher_id = #tid, prod_id = #pid
After that I get status fields NULL.
How to resolve this problem?
Edit:
I tried:
set status = if((select #var:=status from (select status from t1 where teacher_id=#tid and prod_id=#pid) as tmp)=2 and #stts=0,#var,#stts),
But result status 2 changed to 0.
Table schema:
CREATE TABLE `table` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`teacher_id` VARCHAR(20) NOT NULL COLLATE 'utf8_unicode_ci',
`status` INT(11) NULL DEFAULT NULL,
`prod_id` VARCHAR(10) NOT NULL COLLATE 'utf8_unicode_ci',
PRIMARY KEY (`id`),
UNIQUE INDEX `teacher_id_UNIQUE` (`teacher_id`, `prod_id`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
ROW_FORMAT=COMPACT
AUTO_INCREMENT=2053;
Real data:
| id | teacher_id | status | prod_id |
+-----+------------+--------+---------+
| 1 | a1 | 1 | 15 |
| 2 | a1 | 1 | 16 |
| 3 | a1 | 0 | 17 |
| 4 | a2 | 2 | 16 |
| 5 | a2 | 2 | 18 |
| 6 | a3 | 0 | 15 |
| 7 | a3 | 1 | 20 |
File data:
| teacher_id | status | prod_id |
+------------+--------+---------+
| a1 | 0 | 15 |
| a1 | 1 | 16 |
| a1 | 0 | 17 |
| a2 | 1 | 16 |
| a2 | 0 | 18 |
| a3 | 1 | 15 |
| a3 | 1 | 20 |
My temporary solution:
load data local
infile '".$file."'
into table table_tmp
fields terminated by ',' enclosed by '\"'
(teacher_id,
teacher_name,
email,
prod_id,
tca_form_type,
prod_company,
prod_name,
status);
INSERT INTO table
(teacher_id, teacher_name, email, status, prod_id, tca_form_type, prod_company, prod_name)
SELECT teacher_id, teacher_name, email, `status`, prod_id, tca_form_type, prod_company, prod_name FROM table_tmp
ON DUPLICATE KEY UPDATE table.status = IF(table.status = 2 and VALUES(status) = 0, table.status, VALUES(status));
I think this should suffice:
load data local
infile '".$file."'
replace
into table t1
fields terminated by ',' enclosed by '\"'
(#tid,
teacher_name,
email,
#pid,
tca_form_type,
prod_company,
prod_name,
#stts)
set status = if(status = 2 and #stts = 0, status, #stts),
teacher_id = #tid, prod_id = #pid;
If this doesn't help, you can try with the values() function, although it says that it's for the INSERT ... ON DUPLICATE KEY UPDATE statement.
In an INSERT ... ON DUPLICATE KEY UPDATE statement, you can use the VALUES(col_name) function in the UPDATE clause to refer to column values from the INSERT portion of the statement. In other words, VALUES(col_name) in the UPDATE clause refers to the value of col_name that would be inserted, had no duplicate-key conflict occurred. This function is especially useful in multiple-row inserts. The VALUES() function is meaningful only in the ON DUPLICATE KEY UPDATE clause of INSERT statements and returns NULL otherwise. See Section 13.2.5.3, “INSERT ... ON DUPLICATE KEY UPDATE Syntax”.
If that doesn't help either, please provide the table schema and so on, so we can have a try ourselfs and don't have to guess.
Related
table milestoneeventI have three tables file and milestone event. I want to count milestones but by Company.
For example, if I want to count number of last milestone added for the milestone id=1, I do this:
select count('id') as st
from (
select idfile,
max(idmilestone) as max_idmilestone
from milestoneevent
group by idfile)
d where max_idmilestone =1
my problem is how to count them but for each company in table file I have column company. See the picture for more details
Statement should look like this
SELECT d.Comp,count(*),d.max_idmilestone FROM (
SELECT Comp, max(idmilestone) as max_idmilestone, count(idmilestone) as number FROM milestoneevent
INNER JOIN file ON file.id = idfile
GROUP BY idfile, Comp
) d GROUP BY d.max_idmilestone, d.Comp
In the subquery it give you the max(idmilestone) for every company but only if one milestone exists for a idfile, than count how many a max_idmilestone is occuring.
The Result of my test is
+-----------+----------+---+
| Comp | count(*) | |
+-----------+----------+---+
| Microsoft | 5 | 1 |
| Oracle | 1 | 1 |
| Microsoft | 2 | 2 |
| Oracle | 1 | 2 |
+-----------+----------+---+
**Query for Company or milestoneid
If you want to query for Company or max_idmilestone just do this
SELECT d.Comp,count(*),d.max_idmilestone FROM (
SELECT Comp, max(idmilestone) as max_idmilestone, count(idmilestone) as number FROM milestoneevent
INNER JOIN file ON file.id = idfile
WHERE Comp = "Microsoft"
GROUP BY idfile, Comp
) d
WHERE d.max_idmilestone = 1
GROUP BY d.max_idmilestone, d.Comp
Output
+-----------+----------+---+
| Comp | count(*) | |
+-----------+----------+---+
| Microsoft | 5 | 1 |
+-----------+----------+---+
For My Test I used the following structure. Skipped some columns which are not necessary for the test
CREATE TABLE `milestoneevent` (
`id` INT(22) NOT NULL auto_increment,
`idfile` INT(64) NOT NULL,
`idmilestone` INT(64) NOT NULL,
`company` VARCHAR(64) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `file` (
`id` int(22) NOT NULL AUTO_INCREMENT,
`Comp` varchar(64) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
Data of the test
+----+--------+-------------+
| id | idfile | idmilestone |
+----+--------+-------------+
| 1 | 1 | 1 |
| 2 | 10 | 1 |
| 3 | 11 | 1 |
| 4 | 12 | 1 |
| 5 | 13 | 1 |
| 6 | 14 | 1 |
| 7 | 15 | 1 |
| 8 | 16 | 2 |
| 9 | 14 | 2 |
| 10 | 18 | 2 |
+----+--------+-------------+
+----+-----------+
| id | Comp |
+----+-----------+
| 1 | Microsoft |
| 10 | Microsoft |
| 11 | Microsoft |
| 12 | Microsoft |
| 13 | Microsoft |
| 14 | Microsoft |
| 15 | Oracle |
| 16 | Oracle |
| 18 | Microsoft |
+----+-----------+
I have 2 tables in my demos database, in which I join them based on 2 keys, here I would like to count distinct of matched result,
my first table
MariaDB [demos]> select * from main_info;
+------+------+-------+-------+----------+
| key1 | key2 | info1 | info2 | date |
+------+------+-------+-------+----------+
| 1 | 1 | 15 | 90 | 20120501 |
| 1 | 2 | 14 | 92 | 20120601 |
| 1 | 3 | 15 | 82 | 20120801 |
| 2 | 1 | 17 | 90 | 20130302 |
| 2 | 2 | 16 | 88 | 20130601 |
+------+------+-------+-------+----------+
5 rows in set (0.00 sec)
And my second table
MariaDB [demos]> select * from product1;
+------+------+--------+--------------+
| key1 | key2 | serial | product_data |
+------+------+--------+--------------+
| 1 | 1 | 0 | NaN |
| 1 | 1 | 1 | NaN |
| 1 | 1 | 2 | NaN |
| 1 | 1 | 3 | NaN |
| 1 | 2 | 0 | 12.556 |
| 1 | 2 | 1 | 13.335 |
| 1 | 3 | 1 | NaN |
| 1 | 3 | 2 | 13.556 |
| 1 | 3 | 3 | 14.556 |
| 2 | 1 | 0 | 12.556 |
| 2 | 1 | 1 | 13.553 |
| 2 | 1 | 2 | NaN |
+------+------+--------+--------------+
12 rows in set (0.00 sec)
So distinct count of field serial is as follows, where serial is not zero
MariaDB [demos]> select count(distinct a.key1,a.key2) as serial_count from main_info a,product1 b where a.key1=b.key1 and a.key2=b.key2 and b.serial !=0;
+--------------+
| serial_count |
+--------------+
| 4 |
+--------------+
1 row in set (0.00 sec)
and distinct count of field product_data is as follows where product_data is not NaN
MariaDB [demos]> select count(distinct a.key1,a.key2) as product_count from main_info a,product1 b where a.key1=b.key1 and a.key2=b.key2 and b.product_data !='NaN';
+---------------+
| product_count |
+---------------+
| 3 |
+---------------+
1 row in set (0.00 sec)
In my original application I have many columns in my table, finally I would like to get result like below using single query, at present I am doing multiple query using PHP which is taking long time because for example if I have 100 columns, I have to execute function 100 times like above, so please someone guide me to speed up my application
+--------------+---------------+
| serial_count |product_count |
+--------------+---------------+
| 4 | 3 |
+--------------+---------------+
Below is structure of tables
DROP TABLE IF EXISTS `main_info`;
CREATE TABLE `main_info` (
`key1` int(11) NOT NULL,
`key2` int(11) NOT NULL,
`info1` int(11) NOT NULL,
`info2` int(11) NOT NULL,
`date` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
LOCK TABLES `main_info` WRITE;
INSERT INTO `main_info` VALUES (1,1,15,90,20120501),(1,2,14,92,20120601),(1,3,15,82,20120801),(2,1,17,90,20130302),(2,2,16,88,20130601);
UNLOCK TABLES;
DROP TABLE IF EXISTS `product1`;
CREATE TABLE `product1` (
`key1` int(11) NOT NULL,
`key2` int(11) NOT NULL,
`serial` int(11) NOT NULL,
`product_data` varchar(1000) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
LOCK TABLES `product1` WRITE;
INSERT INTO `product1` VALUES (1,1,0,'NaN'),(1,1,1,'NaN'),(1,1,2,'NaN'),(1,1,3,'NaN'),(1,2,0,'12.556'),(1,2,1,'13.335'),(1,3,1,'NaN'),(1,3,2,'13.556'),(1,3,3,'14.556'),(2,1,0,'12.556'),(2,1,1,'13.553'),(2,1,2,'NaN');
UNLOCK TABLES;
I didn't understand this why datetype changed, if I run on terminal
$ mysql -u root -p demos -e 'select key1,if(key1 !=0,key1,999.999) as `test1` from main_info'
Enter password:
+------+-------+
| key1 | test1 |
+------+-------+
| 1 | 1.000 |
| 1 | 1.000 |
| 1 | 1.000 |
| 2 | 2.000 |
| 2 | 2.000 |
+------+-------+
I expect it should be integer if IF condition is true
You can do it in a single query using conditional aggregation:
select count(distinct if(b.product_data !='NaN',a.key1, null),
if(b.product_data !='NaN',a.key2, null)) as product_count,
count(distinct if(b.serial !=0,a.key1, null),
if(b.serial !=0,a.key2, null)) as serial_count
from main_info a
inner join product1 b on a.key1=b.key1 and a.key2=b.key2
Output:
product_count serial_count
-----------------------------
3 4
Demo here
Edit: Credit goes to #Paul Spiegel
The query can be simplified using CONCAT:
select count(distinct if(b.product_data !='NaN',
CONCAT(a.key1, ',', a.key2),
null)) as product_count,
count(distinct if(b.serial !=0,
CONCAT(a.key1, ',', a.key2),
null)) as serial_count
from main_info a
inner join product1 b on a.key1=b.key1 and a.key2=b.key2
I'm trying to add bonus points for users every 2 days. But I'm not sure how to join the users table and get the user_bonus value which indicates the last time a user received a bonus. Can this be done in one query?
Insert query:
INSERT INTO points_plus (user_id, points) VALUES (?,?);
This would be the 2 day interval which needs to be checked:
user_bonus <= NOW() - INTERVAL 2 DAY
users table(part of it)
+-------------+--------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+-------------------+-----------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| weekly_mail | datetime | YES | | NULL | |
| user_bonus | datetime | YES | | NULL | |
| join_date | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------------+--------------+------+-----+-------------------+-----------------------------+
points_plus table
+----+---------+--------+---------------------+
| id | user_id | points | date |
+----+---------+--------+---------------------+
| 18 | 13 | 300 | 2015-10-07 12:06:39 |
| 43 | 13 | 99 | 2015-10-18 14:16:50 |
| 45 | 13 | 103 | 2015-10-19 05:49:49 |
+----+---------+--------+---------------------+
You can try this.
INSERT INTO points_plus (user_id, points)
SELECT id, $points
FROM users
WHERE user_bonus <= NOW() - INTERVAL 2 DAY
I have a MySQL database storing persons and their associated characteristics.
person table:
+----+--------+
| id | name |
+----+--------+
| 1 | Bella |
| 2 | Jacob |
| 3 | Edward |
| 4 | Renée |
| 5 | Alice |
+----+--------+
feature table:
+----+----------+
| id | name |
+----+----------+
| 1 | Bravery |
| 2 | Shyness |
| 3 | Kindness |
| 4 | Madness |
+----+----------+
person_features table:
+-----------+------------+-------+
| person_id | feature_id | value |
+-----------+------------+-------+
| 1 | 1 | 50 |
| 1 | 2 | 84 |
| 1 | 4 | 10 |
| 2 | 1 | 8 |
| 2 | 2 | 78 |
| 2 | 4 | 41 |
| 3 | 3 | 27 |
| 4 | 1 | 36 |
| 4 | 3 | 64 |
| 5 | 2 | 78 |
| 5 | 3 | 2 |
+-----------+------------+-------+
Let's say I want the list of all the persons ordered by descending shyness, kindness and
bravery (with the value of these features for each person):
+--------+---------+----------+---------+
| person | Shyness | Kindness | Bravery |
+--------+---------+----------+---------+
| Bella | 84 | NULL | 50 |
| Alice | 78 | 2 | NULL |
| Jacob | 78 | NULL | 8 |
| Renée | NULL | 64 | 36 |
| Edward | NULL | 27 | NULL |
+--------+---------+----------+---------+
I currently use this dynamically generated query:
SELECT person.name, pf2.value, pf3.value, pf1.value
FROM person
LEFT JOIN person_features pf2 ON person.id = pf2.person_id AND pf2.feature_id = 2
LEFT JOIN person_features pf3 ON person.id = pf3.person_id AND pf3.feature_id = 3
LEFT JOIN person_features pf1 ON person.id = pf1.person_id AND pf1.feature_id = 1
ORDER BY pf2.value DESC, pf3.value DESC, pf1.value DESC, person.name;
But it's a little slow with many features, because I must add a left join for each one. So, is there a way to use a more universal static query instead of a dynamic one? Even if it means a post-processing treatment in my PHP script to regroup data.
CREATE statements:
CREATE TABLE `feature` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
CREATE TABLE `person` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
CREATE TABLE `person_features` (
`person_id` int(11) NOT NULL,
`feature_id` int(11) NOT NULL,
`value` int(11) NOT NULL,
PRIMARY KEY (`person_id`,`feature_id`),
KEY `feature_id` (`feature_id`),
CONSTRAINT `person_features_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`),
CONSTRAINT `person_features_ibfk_2` FOREIGN KEY (`feature_id`) REFERENCES `feature` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Result of EXPLAIN:
+----+-------------+--------+--------+--------------------+---------+---------+----------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+--------+--------------------+---------+---------+----------------------+------+---------------------------------+
| 1 | SIMPLE | person | ALL | NULL | NULL | NULL | NULL | 5 | Using temporary; Using filesort |
| 1 | SIMPLE | pf2 | eq_ref | PRIMARY,feature_id | PRIMARY | 8 | test.person.id,const | 1 | |
| 1 | SIMPLE | pf3 | eq_ref | PRIMARY,feature_id | PRIMARY | 8 | test.person.id,const | 1 | |
| 1 | SIMPLE | pf1 | eq_ref | PRIMARY,feature_id | PRIMARY | 8 | test.person.id,const | 1 | |
+----+-------------+--------+--------+--------------------+---------+---------+----------------------+------+---------------------------------+
I'm not sure if this would be faster, but you can try using conditional aggregation:
select p.name,
max(case when pf.feature_id = 2 then value end) as shyness,
max(case when pf.feature_id = 3 then value end) as kindness,
max(case when pf.feature_id = 1 then value end) as bravery
from person p join
person_features pf
on p.person_id = pf.person_id
group by p.name
order by shyness desc, kindess desc, bravery desc;
Also, an index on person_features(person_id, feature_id, value) would speed up your query (as well as this one).
I have 3 mysql tables containing a few fields. Please refer to the following
-------- -------- --------
table 1 | table 2 | table 3
-------- -------- --------
a_id | b_id | email
| a_id
name | status | b_id
email_1 | date | name
phone | ref | phone
address | email_2 | address
state | from | state
| status
| date
| ref
| from
The email_1 and email_2 is exactly same.
I need to populate the table3 fields with all table1 and table2 data. But I need to store them in one row based on email. So they look like following:
=================================================================================
table 3
=================================================================================
email | a_id | b_id | name | phone | address | state | status | date | ref | from
------+------+------+------+-------+---------+-------+--------+------+-----+-----
a#x.co| 9 | 112 | John | 999 | xxxx | NY | 0 | 15Jue| dave| y
------+------+------+------+-------+---------+-------+--------+------+-----+-----
b#x.co| 6 | 338 | Sue | 909 | xxxx | NY | 1 | 12Jue| kell| z
------+------+------+------+-------+---------+-------+--------+------+-----+-----
c#x.co| 3 | 152 | John | 679 | xxxx | NY | 1 | 10Jue| lois| g
------+------+------+------+-------+---------+-------+--------+------+-----+-----
d#x.co| 8 | 145 | John | 599 | xxxx | NY | 0 | 8Jue | sue | f
I can't figure it out how to do that. I'm using core php, mysql. Any help please?
Thanks!
I would use something like this for mysql:
insert into table_3
(
`email`,
`a_id`,
`b_id`,
`name`,
`phone`,
`address`,
`state`,
`status`,
`date`,
`ref`,
`from`
)
select
`a`.`email_1`,
`a`.`a_id`,
`b`.`b_id`,
`a`.`name`,
`a`.`phone`,
`a`.`address`,
`a`.`state`,
`b`.`status`,
`b`.`date`,
`b`.`ref`,
`b`.`from`
from
table_1 as `a`
inner join
table_2 as `b` on `a`.`email_1` = `b`.`email_2`
But you should probably go read up on MySQL insert syntax to see it's power, and on joining data :)
insert into table_3(`email`,`a_id`,`b_id`,`name`,`phone`,`address`,`state`,`status`,`date`,`ref`,`from`)
select `email_1`,`a_id`,`b_id`,`name`,`phone`,`address`,`state`,`status`,`date`,`ref`,`from`
from table_1,table_2
where email_1=email_2;