SQL Upvote Downvote system - php

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

Related

Update/Insert Large table records based on another Table ReferenceID.

I have an Internal Inventory system with the below 3 tables as
a. Stocks - Daily updated from a CSV file.
---------------------------------
| id | MODELNO | Discount | MRP |
---------------------------------
| 1 | MODEL_1 | 40% | 900 |
| 2 | MODEL_A | 20% | 600 |
---------------------------------
Everyday this table is truncated and new stocks data are imported from a CSV file of a merchant.(around 6 Million records)
b. Cloths Master - The master clothes database
----------------------------------------
| ref_id | MODELNO | Name | MRP |
----------------------------------------
| 80 | MODEL_1 |Some Dress | 900 |
| 81 | MODEL_A |Another Dress| 600 |
----------------------------------------
The MODELNO is unique and ref_id the primary key. This table is part of the internal Inventory application (Has around 4.5 Million records)
c. Inventory table - It's part of the internal Applications
-------------------------------------------------
| id | ref_id | Name | MRP | status |
-------------------------------------------------
| 1 | 80 |Some Dress | 900 | ACTIVE |
| 2 | 81 |Another Dress| 600 | INACTIVE |
--------------------------------------------------
This table stores the available inventory for the product, based on the stocks and if the discount if above 40% the product is ACTIVE else by default INACTIVE.
The required functionality is that every day I need to run a script that would loop throught stock table records, and for the MODELNO update the stock on the Inventory table and If the record in Inventory table does not exist then it needs to be added.
What I have tried till now is a PHP script that would.
a. Firstly, set status in Inventory table for all records to INACTIVE.
b. And for each of the records in the stocks table, check if the MODELNO exists in Cloths Master table.
b. If the records exists then get the ref_id, and check if the ref_id exists in the Inventory Table and Update/Insert record accordingly.
The problem is that the script takes more than 8+ Hrs to complete.
Can you a suggest an efficient way, that can be used to implement the above functionality.
Note :
All the inserts and updated to the Inventory table are done using CodeIgniter's batch insert/update function.
I set all the status to INACTIVE, as there may be few products that are not present in the Stock DB.
The question in this case which comes in mind is - why not using a trigger ?
Create a table so_stocks
CREATE TABLE IF NOT EXISTS `so_stocks` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`MODELNO` varchar(50) COLLATE uft8_general_ci NOT NULL DEFAULT '0',
`Discount` int(10) DEFAULT '0',
`MRP` int(11) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=uft8_general_ci;
INSERT INTO `so_stocks` (`id`, `MODELNO`, `Discount`, `MRP`) VALUES
(1, 'MODEL_1', 40, 900),
(2, 'MODEL_A', 20, 600);
Create a table so_inventory
CREATE TABLE `so_inventory` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`ref_id` INT(11) NOT NULL DEFAULT '0',
`Name` VARCHAR(255) NOT NULL DEFAULT '0' COLLATE 'uft8_general_ci',
`MRP` INT(11) NOT NULL DEFAULT '0',
`status` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
COLLATE='uft8_general_ci'
ENGINE=MyISAM
AUTO_INCREMENT=1
;
And finally a table so_cloths
CREATE TABLE `so_cloths` (
`ref_id` INT(11) NOT NULL AUTO_INCREMENT,
`MODELNO` VARCHAR(50) NOT NULL DEFAULT '0' COLLATE 'uft8_general_ci',
`Name` VARCHAR(255) NOT NULL DEFAULT '0' COLLATE 'uft8_general_ci',
`MRP` INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`ref_id`)
)
COLLATE='uft8_general_ci'
ENGINE=MyISAM
AUTO_INCREMENT=1
;
And now the trigger
CREATE DEFINER=`root`#`::1` TRIGGER `so_cloths_after_insert` AFTER INSERT ON `so_cloths` FOR EACH ROW BEGIN
INSERT INTO so_inventory (ref_id,Name,MRP,status)
select sc.ref_id,sc.Name, sc.MRP, if (ss.Discount >= 40, 1,0) AS active from so_cloths AS sc
LEFT JOIN so_stocks AS ss ON (sc.MODELNO = ss.MODELNO)
WHERE sc.ref_id = new.ref_id;
END
Everytime you insert something into so_cloths an insert would be made into so_inventory.
Obviously it depends whether you want to insert data after inserting it into so_stocks or into so_cloths - you've to decide it - but the example should give you some insight.
The definer in the trigger statement has to be changed to your settings

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;

How do I make a SQL Command with INSERT AND COUNT

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.

MySQL for Test Website

I am making a website similar to Moodle. It basically holds tests for students. The confusion comes in when allowing multiple types of questions on the tests and how to create the tables to store the data.
The test_info table will contain the test ID and description.
The test table will contain Test ID and Question ID pairs.
To get the questions for a test this will require a "SELECT * FROM test WHERE testID=$tID" which will take a substantial amount of time to execute when the database gets large.
Originally the questions table contained the question, 4 possibilities and the answer.
How should I store the data for multiple questions and multiple types of questions in a database?
For Example:
Test 51 - "Intro Mathmatics"
Question 1: What is 2+2?
A: 4 B: 12
C: 7 D: 8
Question 2: (0,103) is the range for the equation y=2x/(100x)?
True False
This results in data with 2 different sizes
Questions:
| Question | A | B | C | D | Correct |
| Question | Correct |
If I store these in 1 table it will waste 4 50Char Var-Chars per question and if I store these in 2 separate tables, how will the SELECT know which table to select from?
Questions:
| TestID | TableID | QuestionID |
Questions1:
| Ques | A | B | C | D | Correct |
Questions2:
| Ques | A | B | C | D | Correct |
What a nightmare.
Put the answer in their own table:
answers (answer_id, question_id, description, sequence)
and put the correct answer_id in the question table.
An empty VARCHAR(50) only needs six bits, which means that it will (most likely) take up one byte only on the disk. The VAR in VARCHAR means that the space usage will adapt to the actual data. This means that using one table will "waste" only four bytes per question.
Since you have two types of questions that you handle in two different ways in the code, your two-table approach is viable as well.
The recommended approach is:
Note that four-answer questions and yes-no questions are both special cases of a multiple-choice question. Store these in the database. One possible schema:
question: question_id (PK), test_id (FK), text
answer: answer_id (PK), question_id (FK), text, is_correct
PK = primary key, FK = foreign key
I think you data structure will be like this:
Table1 :Test
id:
TestName:
Table2: Questions:
id:
test_id:
Question:
Answer: //say a,b,c,d
Table3:Answers
id:
question_id:
Anwser Option: //say a,b,c,d
Answer:
Sql For tables with data:
The data will help you in understanding the structure.
CREATE TABLE IF NOT EXISTS `Tests` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`Test` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
--
-- Dumping data for table `test2`
--
INSERT INTO `test2` (`id`, `Test`) VALUES
(1, 'Test1');
//////////////////////////////////////
CREATE TABLE IF NOT EXISTS `questions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`test_id` int(11) NOT NULL,
`Question` varchar(255) NOT NULL,
`Answer` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
--
-- Dumping data for table `questions`
--
INSERT INTO `questions` (`id`, `test_id`, `Question`, `Answer`) VALUES
(1, 1, 'question1', 'a'),
(2, 2, 'Question2', 'd');
////////////////////////////////////////////////////
CREATE TABLE IF NOT EXISTS `answers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`question_id` int(11) NOT NULL,
`answer_option` varchar(10) NOT NULL,
`Answer` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ;
--
-- Dumping data for table `answers`
--
INSERT INTO `answers` (`id`, `question_id`, `answer_option`, `Answer`) VALUES
(1, 1, 'a', 'True'),
(2, 1, 'b', 'False'),
(3, 2, 'a', 'Asnwer1'),
(4, 2, 'b', 'Answer2'),
(5, 2, 'c', 'Answer3'),
(6, 2, 'd', 'Answer4'),
(7, 2, 'e', 'Answer5');

Categories