How do I make a SQL Command with INSERT AND COUNT - php

I don't know how to COUNT a column named id. I tried
mysql_query("INSERT INTO `servers` (`user_id`, `ip`, `port`, `banner`, `disabled`, `vip`,`premium`, `name`, `status`, `votifier_key`, `votifier_port`, `country`)
VALUES ('$session_user_id', '$ip', '$port', 's=.'id'.back', '$disabled', 0,'false', '$name', '1', '$votifier', '$votPort', '$country')");
But it's not working, because I couldn't get id. Can someone help?

You need to use INSERT ... SELECT request.
Suppose, we have an empty table test:
test
|----+-------|
| id | value |
|----+-------|
CREATE TABLE IF NOT EXISTS `test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`value` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
When we run this SQL request:
INSERT INTO test (value) SELECT COUNT(*) FROM `test`
we shall sequentially get test filling up with data:
| id | value |
|----+-------|
| 1 | 0 |
| 2 | 1 |
| 3 | 2 |
Use this approach for your table, and you'll get what you need.

Related

Executing an update and checking for duplicates at same time in MySQL/Laravel

I am using Laravel 4.2 and have a query:
DB::table('data')->whereIn('t_id', $new_ids);
->whereNotIn('l_id', $old_ids);
->groupBy('l_id')->update(array('t_id' => $new_t_id));
This causes an error:
500 - SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1569648-7302' for key 'data_l_id_t_id_unique' (SQL: update `data` set `t_id` = 7302 where `t_id` in (4772, 4860, 4861, 5653, 6396, 6743) and `l_id` not in (2994190)) # /
The problems seems to be with groupBy() clause which is not being executed, thus making duplicate l_id to be pulled into the query:
mysql> select l_id from data where t_id=7302;
+---------+
| l_id |
+---------+
| 2994190 |
+---------+
1 row in set (0.00 sec)
mysql> select l_id from data where t_id in (4772, 4860, 4861, 5653, 6396, 6743);
+---------+
| l_id |
+---------+
| 1569648 |
| 1593870 |
| 1594096 |
| 1628872 |
| 1569648 |
| 1593870 |
| 1594096 |
| 1628872 |
| 1569648 |
| 1593870 |
| 1594096 |
| 1628872 |
| 1879092 |
| 2283518 |
| 2284586 |
| 2604466 |
+---------+
16 rows in set (0.00 sec)
mysql> select l_id from data where t_id in (4772, 4860, 4861, 5653, 6396, 6743) GROUP BY l_id;
+---------+
| l_id |
+---------+
| 1569648 |
| 1593870 |
| 1594096 |
| 1628872 |
| 1879092 |
| 2283518 |
| 2284586 |
| 2604466 |
+---------+
8 rows in set (0.00 sec)
Schema:
mysql> show create table data;
CREATE TABLE `data` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`l_id` bigint(20) unsigned NOT NULL,
`t_id` bigint(20) unsigned NOT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `data_l_id_tag_id_unique` (`l_id`,`t_id`),
KEY `data_t_id_foreign` (`t_id`),
CONSTRAINT `data_l_id_foreign` FOREIGN KEY (`l_id`) REFERENCES `lis` (`id`),
CONSTRAINT `data_t_id_foreign` FOREIGN KEY (`t_id`) REFERENCES `tas` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4544794 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Basically I need to update t_id for certain l_ids but still ensure no duplicate t_id/l_id happen. I could do this by looping through each t_id and checking for duplicates before updating but thought a shortcut via groupBy() would be a better way of doing it.
Is it possible to make Laravel do a groupBy() while updating? More generally can an update be executed while checking for duplicates, even in plain SQL?
Edit: Separating update from group by
Making UPDATE and GROUP BY seperate helps resolve GROUP BY problem but not duplicate problem:
$required_l_ids = DB::table('data')->whereIn('t_id', $new_ids);
->whereNotIn('l_id', $old_ids);
->groupBy('l_id')->lists('l_id');
if ( !empty($required_l_ids) ) {
DB::table('data')->whereIn('l_id', $required_l_ids)->whereIn('t_id', $new_ids)->update(array('t_id' => $new_tag_id));
}
Still gives an error:
500 - SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1593870-7302' for key 'data_l_id_t_id_unique' (SQL: update `data` set `t_id` = 7302 where `l_id` in (1593870, 1594096, 1628872, 1879092, 2283518, 2284586, 2604466) and `t_id` in (4772, 4860, 4861, 5653, 6396, 6743)) # /
Edit 2: Sample data
CREATE TABLE `data` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`l_id` bigint(20) unsigned NOT NULL,
`t_id` bigint(20) unsigned NOT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `data_l_id_t_id_unique` (`l_id`,`t_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4544794 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT into data (l_id, t_id) VALUES (1569648,7302);
INSERT into data (l_id, t_id) VALUES (2994190,7302);
INSERT into data (l_id, t_id) VALUES (1593870,4772);
INSERT into data (l_id, t_id) VALUES (1594096,4772);
INSERT into data (l_id, t_id) VALUES (1628872,4772);
INSERT into data (l_id, t_id) VALUES (1569648,4860);
INSERT into data (l_id, t_id) VALUES (1593870,4860);
INSERT into data (l_id, t_id) VALUES (1594096,4860);
INSERT into data (l_id, t_id) VALUES (1628872,4860);
INSERT into data (l_id, t_id) VALUES (1569648,4861);
INSERT into data (l_id, t_id) VALUES (1593870,4861);
INSERT into data (l_id, t_id) VALUES (1594096,4861);
INSERT into data (l_id, t_id) VALUES (1628872,4861);
INSERT into data (l_id, t_id) VALUES (1879092,5653);
INSERT into data (l_id, t_id) VALUES (2283518,6396);
INSERT into data (l_id, t_id) VALUES (2284586,6396);
INSERT into data (l_id, t_id) VALUES (2604466,6743);
UPDATE data AS d1 LEFT JOIN data AS d2 ON d1.l_id = d2.l_id AND d2.t_id = 7302 SET d1.t_id = 7302 WHERE d1.t_id IN (4772,4860,4861,5653,6396,6743) AND d1.l_id NOT IN (1569648,2994190) AND d2.l_id IS NULL;
sqlfiddle: http://sqlfiddle.com/#!9/e9a50
Error: Duplicate entry '1593870-7302' for key 'data_l_id_t_id_unique'
I don't know the Laravel syntax, but I think this is the MySQL syntax for what you want:
UPDATE data AS d1
JOIN (SELECT l_id, MIN(t_id) AS min_t_id
FROM data
WHERE d1.t_id IN ($new_ids)
AND d1.l_id NOT IN ($old_ids)
GROUP BY l_id) AS d3 ON d1.l_id = d3.l_id AND d1.t_id = d3.min_t_id
LEFT JOIN data AS d2 ON d1.l_id = d2.l_id AND d2.t_id = $new_tag_id
SET d1.t_id = $new_tag_id
WHERE d2.l_id IS NULL
This combines an UPDATE with the LEFT JOIN/NULL pattern in Return row only if value doesn't exist
The first JOIN makes sure that only one row for each l_id is updated, so you don't create duplicates. It arbitrarily chooses the lowest t_id to replace.
DEMO

How to update a row with multiple images which has only single image inserted initially in php

I have a table with columns id,image and organisation name.I have inserted single image for each organisation initially but i need to update it with multiple images for each organisation.I am using php ver 5.4.16 and mysql ver 5.6.12.
Try to use a separator, for example use comma and store it like this in your table :
id image organization
1 path_to/img1.png org_name1
2 path_to/img1.png,path_to/img2.png org_name2
and later, after you extract the record, use explode function to extract it to an array like this :
$images = explode(",", $data->image);
PS : please give enough length for the image field, for example, give it varchar(4000), this is to make sure there will be no string truncation
Split the table in two and use the id of your table as foreign key in the new image table. ("normalization" and "relations" should be your search tags) https://en.wikipedia.org/wiki/Database_normalization
Or if you can't you should use json to insert multiple content. http://php.net/manual/en/book.json.php
You need to add a new table named "image" with columns :
- id_img
- image
- ref_organisation_id (foreign_key)
The best solution, in my opinion, to your problem would be to slightly redesign your database schema - the existing table will not be able to store multiple images for the same company judging by the overview of the tables you gave in the question.
There ought to be a table for orgainisations and another table for images associated with those organisations. The images table would have a key that links to the organisations table.
A very quickly put together example database structure
+----+------------------+
| id | name |
+----+------------------+
| 1 | ACME Web Company |
| 2 | ACME ISP |
+----+------------------+
+----+--------+------------+
| id | org_id | image |
+----+--------+------------+
| 1 | 1 | logo.jpg |
| 2 | 1 | banner.jpg |
| 3 | 1 | badge.png |
| 4 | 2 | logo.jpg |
| 5 | 2 | banner.gif |
+----+--------+------------+
create table if not exists `organisations` (
`id` int(10) unsigned not null auto_increment,
`name` varchar(50) not null,
primary key (`id`)
) engine=innodb auto_increment=3 default charset=utf8;
insert into `organisations` (`id`, `name`) values
(1, 'acme web company'),
(2, 'acme isp');
create table if not exists `org_images` (
`id` int(10) unsigned not null auto_increment,
`org_id` int(10) unsigned not null,
`image` varchar(50) not null,
primary key (`id`),
key `org_id` (`org_id`),
constraint `fk_org` foreign key (`org_id`) references `organisations` (`id`) on delete cascade on update cascade
) engine=innodb auto_increment=6 default charset=utf8;
insert into `org_images` (`id`, `org_id`, `image`) values
(1, 1, 'logo.jpg'),
(2, 1, 'banner.jpg'),
(3, 1, 'badge.png'),
(4, 2, 'logo.jpg'),
(5, 2, 'banner.gif');

Mysql - On Duplicate Key Update not working for 2 keys

Hello I have a table with two unique keys profile_id and date. I don't know where is the problem but my query is not working.
Table:
CREATE TABLE `profile_views`
(\n `id` int(11) NOT NULL AUTO_INCREMENT,
\n `profile_id` varchar(45) DEFAULT NULL,
\n `counter` varchar(45) DEFAULT NULL,
\n `date` date DEFAULT NULL,
\n PRIMARY KEY (`id`),
\n UNIQUE KEY `date_UNIQUE` (`date`),
\n UNIQUE KEY `profile_id_UNIQUE` (`profile_id`)\n
) ENGINE=InnoDB AUTO_INCREMENT=150 DEFAULT CHARSET=latin1'
Data Right Now:
# id , profile_id, counter, date
113, 2 , 36 , 2015-08-27
I issue this command:
INSERT INTO profile_views (profile_id, counter, date)
VALUES (2, 1, '2015-08-28')
ON DUPLICATE KEY UPDATE counter = counter+1;
And
INSERT INTO profile_views (profile_id, counter, date)
VALUES (2, 1, '2015-08-27')
ON DUPLICATE KEY UPDATE counter = counter+1;
In this query i just changed the date so it should insert new row.
My Desired Results:
If i change date still it changing the same profile id counter.
I want to store everyday profile views for each profile id. So if the date and profile id is same its increment the counter otherwise insert new row.
Any help? Thanks.
Schema:
CREATE TABLE `profile_views`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`profile_id` varchar(45) DEFAULT NULL,
`counter` varchar(45) DEFAULT NULL,
`date` date DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `date_UNIQUE` (`date`),
UNIQUE KEY `profile_id_UNIQUE` (`profile_id`)
) ENGINE=InnoDB auto_increment=150;
insert profile_views (id,profile_id,counter,date) values (113,2,36,'2015-08-27');
...
...
select * from profile_views;
+-----+------------+---------+------------+
| id | profile_id | counter | date |
+-----+------------+---------+------------+
| 113 | 2 | 36 | 2015-08-27 |
+-----+------------+---------+------------+
INSERT INTO profile_views (profile_id, counter, date)
VALUES (2, 1, '2015-08-28')
ON DUPLICATE KEY UPDATE counter = counter+1;
-- 2 row(s) affected
select * from profile_views;
+-----+------------+---------+------------+
| id | profile_id | counter | date |
+-----+------------+---------+------------+
| 113 | 2 | 37 | 2015-08-27 |
+-----+------------+---------+------------+
INSERT INTO profile_views (profile_id, counter, date)
VALUES (2, 1, '2015-08-27')
ON DUPLICATE KEY UPDATE counter = counter+1;
-- 2 row(s) affected
select * from profile_views;
+-----+------------+---------+------------+
| id | profile_id | counter | date |
+-----+------------+---------+------------+
| 113 | 2 | 38 | 2015-08-27 |
+-----+------------+---------+------------+
It looks good to me. Each insert on duplicate update has a unique key clash, allowing the update to happen. What clashes? Well the unique key on profile_id does.
What am I missing?
If you lay things out step by step, people can visualize it better :>
Edit: (OP changed his mind)
CREATE TABLE `profile_views`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`profile_id` varchar(45) DEFAULT NULL,
`counter` varchar(45) DEFAULT NULL,
`date` date DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `combo_thingie1` (profile_id,`date`) -- unique composite
) ENGINE=InnoDB auto_increment=150;
insert profile_views (id,profile_id,counter,date) values (113,2,36,'2015-08-27');
... ...
select * from profile_views;
+-----+------------+---------+------------+
| id | profile_id | counter | date |
+-----+------------+---------+------------+
| 113 | 2 | 36 | 2015-08-27 |
+-----+------------+---------+------------+
INSERT INTO profile_views (profile_id, counter, date)
VALUES (2, 1, '2015-08-28')
ON DUPLICATE KEY UPDATE counter = counter+1;
select * from profile_views;
+-----+------------+---------+------------+
| id | profile_id | counter | date |
+-----+------------+---------+------------+
| 113 | 2 | 36 | 2015-08-27 |
| 150 | 2 | 1 | 2015-08-28 |
+-----+------------+---------+------------+
INSERT INTO profile_views (profile_id, counter, date)
VALUES (2, 1, '2015-08-27')
ON DUPLICATE KEY UPDATE counter = counter+1;
select * from profile_views;
+-----+------------+---------+------------+
| id | profile_id | counter | date |
+-----+------------+---------+------------+
| 113 | 2 | 37 | 2015-08-27 |
| 150 | 2 | 1 | 2015-08-28 |
+-----+------------+---------+------------+
I came up with this mad structure - it inserts new records for new dates and then updates on successive insert statements - thus incrementing the counter.
CREATE TABLE `profile_views` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`profile_id` VARCHAR(45) NOT NULL,
`counter` VARCHAR(45) NOT NULL,
`date` DATE NOT NULL,
PRIMARY KEY (`id`, `profile_id`, `date`),
UNIQUE INDEX `profile_id_date` (`profile_id`, `date`),
UNIQUE INDEX `id_profile_id_date` (`id`, `profile_id`, `date`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=267;

SQL Upvote Downvote system

I am currently working on a forum where posts need to have an upvote/downvote system.
My current sql(phpmyadmin) structure is like this:
Table 1 (posts)
| post_id | post_title | post_score |
Table 2 (pvotes)
| pvote_id | fk_post_id | fk_user_id | pvote_score |
I want to somehow make post_score (in table 1), find all pvote_score (table 2) columns and add/subtract them together, where fk_post_id (table 2) is = to post_id (table 1)
This way I hope to make a voting system that only allows every user to vote once, and automatically calculate a posts post_score from the pvote_score values.
EXAMPLE:
user_1 upvotes post_1 inserting following into table 2:
| (pvote_id) 1 | (fk_post_id) 1 | (fk_user_id) 1 | (pvote_score) 1 |
I now want post_score (table 1) to find all entries in table 2 where:
fk_post_id is same as post_id, and thereafter add or subtract the values from pvote_score and make the sum the NEW value of post_score.
I am trying to make it work just like stackoverflows own upvote/downvote system.
EDIT 1:
Question:
I want to know how can I make the post_score column automatically add/subtract the values from pvotes_score and show the sum as its value?
I've created your database structure like this:
CREATE TABLE `posts` (
`post_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`post_title` varchar(50) DEFAULT NULL,
`post_score` int(11) DEFAULT NULL,
PRIMARY KEY (`post_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
INSERT INTO `posts` VALUES (NULL, 'test', 0), (NULL, 'test2', 0);
CREATE TABLE `pvotes` (
`pvote_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`fk_post_id` int(11) DEFAULT NULL,
`fk_user_id` int(11) DEFAULT NULL,
`pvote_score` int(11) DEFAULT NULL,
PRIMARY KEY (`pvote_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
INSERT INTO `pvotes` VALUES (NULL, 1, 0, 2), (NULL, 1, 0, 3), (NULL, 1, 0, -1), (NULL, 2, 0, 2);
This is the query that should do the trick:
UPDATE posts SET post_score = (SELECT SUM(pvote_score) FROM pvotes WHERE fk_post_id = post_id);
The result I've got is this:
post_id | post_title | post_score
1 | test | 4
2 | test2 | 2

Using MySQL, What is the best way to not to select users that exist in a different table?

My problem is the following:
I have two tables; persons and teams, I want to select all the persons with role_id = 2, that exist in persons but not in teams.
Table teams stores the hashes for the team leader who can only lead one team at a time. When creating teams, I just want to show administrators the people who is not currently leading a team, basically exclude all the ones who are already leaders of any given team.
My structure is as follows:
mysql> desc persons;
+-------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| firstname | varchar(9) | YES | | NULL | |
| lastname | varchar(10) | YES | | NULL | |
| role_id | int(2) | YES | | NULL | |
| hash | varchar(32) | NO | UNI | NULL | |
+-------------+-------------+------+-----+---------+-------+
mysql> desc teams;
+--------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
| leader | varchar(32) | NO | | NULL | |
+--------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
My current SQL is as follows:
SELECT CONCAT( `persons`.`firstname` ," ", `persons`.`lastname` ) AS `manager`,
`hash` FROM `persons`
WHERE `persons`.`role_id` =2 AND `persons`.`hash` !=
(SELECT `leader` FROM `teams` );
The latter SQL Query works when the table teams only has 1 record, but as soon as I add another one, MySQL complaints about the subquery producing two records.
In the WHERE Clause, instead of subqueries I've also tried the following:
WHERE `persons`.`role_id` = 2 AND `persons`.`hash` != `teams`.`leader`
but then it complaints about column leader not existing in table teams
I was also thinking about using some kind of inverse LEFT JOIN, but I haven't been able to come up with an optimal solution.
Any help is greatly appreciated!
Thanks
P.S.: Here is the SQL statements should you want to have a scenario similar to mine:
DROP TABLE IF EXISTS `teams`;
CREATE TABLE IF NOT EXISTS `teams` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`leader` varchar(32) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
INSERT INTO `teams` (`id`, `name`, `leader`) VALUES
(1, 'Team 1', '406a3f5892e0fcb22bfc81ae023ce252'),
(2, 'Team 2', 'd0ca479152996c8cabd89151fe844e63');
DROP TABLE IF EXISTS `persons`;
CREATE TABLE IF NOT EXISTS `persons` (
`firstname` varchar(9) DEFAULT NULL,
`lastname` varchar(10) DEFAULT NULL,
`role_id` int(2) DEFAULT NULL,
`hash` varchar(32) NOT NULL,
PRIMARY KEY `hash` (`hash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `persons` (`firstname`, `lastname`, `role_id`,`hash`) VALUES
('John', 'Doe', 2, '406a3f5892e0fcb22bfc81ae023ce252'),
('Jane', 'Doe', 2, 'd0ca479152996c8cabd89151fe844e63'),
('List', 'Me', 2, 'fbde2c4eeee7f455b655fe4805cfe66a'),
('List', 'Me Too', 2, '6dee2c4efae7f452b655abb805cfe66a');
You don't need a subquery to do that. A LEFT JOIN is enough:
SELECT
CONCAT (p.firstname, " ", p.lastname) AS manager
, p.hash
FROM persons p
LEFT JOIN teams t ON p.hash = t.leader
WHERE
p.role_id = 2
AND t.id IS NULL -- the trick
I think you want an IN clause.
SELECT CONCAT( `persons`.`firstname` ," ", `persons`.`lastname` ) AS `manager`,
`hash` FROM `persons`
WHERE `persons`.`role_id` =2 AND `persons`.`hash` NOT IN
(SELECT `leader` FROM `teams` );
As pointed out, this is not optimal. You may want to do a join instead.

Categories