I have a basic system I am creating in which a user creates goals. When the goal is inserted, it is given a value of 0 to the status column. When the goal is completed, the value is updated to 1. So, what I am trying to do is fetch the specific user's (user with the current session) total number of ids (rows for the amount of goals) and then get the values of the status column and then count those. Once the actual status column values have been added, I want to divide that by the total number of id's. I am basically trying to figure out how to get a rate of completion.
I am not certain how I can:
-count the number of total id's for the user.
-get the values of the status column for the user and then add those.
Can anyone point me in the right direction?
Table
Create Table
goals
CREATE TABLE `goals` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`title` text COLLATE utf8_unicode_ci NOT NULL,
`description` text COLLATE utf8_unicode_ci NOT NULL,
`status` int(5) NOT NULL,
`importance` int(5) NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_c
$select_goals_sql = "
SELECT *
FROM goals
WHERE user_id = ?
ORDER BY id DESC
";
if ($select_goals_stmt = $con->prepare($select_goals_sql)) {
$select_goals_stmt->execute(array($user_id));
$rows = $select_goals_stmt->fetchAll(PDO::FETCH_ASSOC);
$goals = array();
foreach ($rows as $row) {
$goal_date = $row['date'];
$fixed_goal_date = fixDate($goal_date);
// the varialbe I will name it $status_completed =
$html = "";
Edit:
$goal_total_sql = "
SELECT sum(status) as sumna,
COUNT(*) as cnt
FROM goals
WHERE user_id = ?
";
if ($goal_total_stmt = $con->prepare($goal_total_sql)) {
$goal_total_stmt->execute(array($user_id));
$rows = $goal_total_stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
$actual_status = $row['status'];
$total_status = $row['id'];
}
}
?>
<div id="main">
<?php
echo "Actual:". $actual_status;
echo "Total". $total_status;
?>
SELECT status_id FROM goals WHERE userId = ? GROUP BY status_id should count the number of ids for each state
SELECT COUNT(*) as goal_count, status FROM goals WHERE user_id = ? GROUP BY status;
This will show you in tabular format the goal_count next to the status.
here is a sqlfiddle:
http://sqlfiddle.com/#!9/1bb23
so using a modified version of your create table (You should be using Innodb and I ommited the Collac for simplicity)
your result should be like this:
+------------+--------+
| goal_count | status |
+------------+--------+
| 1 | 1 |
| 2 | 2 |
| 2 | 3 |
| 2 | 4 |
+------------+--------+
I's hard to tell what you need here because the question title contradicts with body and both with code provided. But as far as I can tell
SELECT sum(status) as summa, COUNT(*) as cnt FROM ...
Related
I want to sort my image list using date or upvotes received. There is also the possibility to use the link of an opened image something likewww.mywebsite.com/images?selected=73723.jpg to open up an image directly while the other sorting terms still apply.
The selected image should be the first element but after that it should again be sorted by date or upvotes as it would normally. Here is what I have:
$sortingstring = "image_uploads.UPVOTES DESC"; // <-- order by upvote
$sortingstring = "image_uploads.THMPATH = '".$selectedCode."'"; // <-- selected image
$query = "SELECT * FROM test_users, image_uploads ORDER BY " . $sortingstring;
In this example we can see the code for upvote sorting and for filtering out the selected image. How can I combine both sorting by upvotes and display the selected image first, it doesn't seem to work no matter what I tried?
Maybe you can do it with the FIELD function, something like this
ORDER BY FIELD(image_uploads.THMPATH, "your code") DESC, image_uploads.UPVOTES DESC
Here is a simple example
CREATE TABLE `items` (
`id` int(11) NOT NULL,
`sort_field` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ALTER TABLE `items` ADD PRIMARY KEY (`id`);
INSERT INTO `items` (`id`, `sort_field`) VALUES
(1, 1),
(2, 3),
(3, 2);
Query
SELECT * FROM items ORDER BY FIELD(items.id, 1) DESC, sort_field DESC
Result
| id | sort_field |
|----|------------|
| 1 | 1 |
| 2 | 3 |
| 3 | 2 |
I'm setting up a script that needs to extract all current contracts owned by a user through transaction history.
Here's the transaction table and some test data:
CREATE TABLE `transaction` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`sender_id` int(11) NOT NULL,
`recipient_id` int(11) NOT NULL,
`contract_id` int(11) NOT NULL,
`created_on` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `sender_id` (`sender_id`,`contract_id`,`tokens`),
KEY `recipient_id` (`recipient_id`,`contract_id`,`tokens`)
);
INSERT INTO `transaction` VALUES
(1,10,20,1,'2019-01-20 15:41:47'),
(2,10,20,2,'2019-01-20 15:41:47'),
(3,30,10,1,'2019-01-20 15:41:47'),
(4,30,10,3,'2019-01-20 15:41:47'),
(5,20,10,2,'2019-01-20 15:41:47');
As output i would like an array with all contract id's for a given user.
Output of the query for user id = 10:
+-------------+
| contract_id |
+-------------+
| 1 |
+-------------+
| 2 |
+-------------+
| 3 |
+-------------+
This is the current code that I have to achieve this. However, it would be nice if it would be one query.
$query = 'SELECT DISTINCT contract_id
FROM transaction
WHERE tokens IS NULL
ORDER BY created_on DESC';
$statement = $this->entityManager
->getConnection()
->prepare($query);
$statement->execute();
$contracts = [];
foreach ($statement->fetchAll() as $row) {
$query = 'SELECT *
FROM transaction
WHERE contract_id = :contract
AND tokens IS NULL
ORDER BY created_on DESC';
$statement = $this->entityManager
->getConnection()
->prepare($query);
$statement->execute([
'contract' => $row['contract_id']
]);
$result = $statement->fetch();
if ((int) $result['recipient_id'] !== $user->getId()) {
continue;
}
$contracts[] = $result['contract_id'];
}
return $contracts;
Take the minimal possible answer, use DISTINCT to prevent duplicates in the output. ORDER BY is optional.
SELECT DISTINCT contract_id
FROM transactions
WHERE recipient_id = :id
ORDER BY contract_id
Your recipient_id index will help will this query.
Firstly you didn't give information as to who the contract owner is based on your database fields. Couldn't tell if it was sender_id or recipient_id. Your question was also a little vague in that I couldn't work out if you wanted numerous associative arrays based on the data.
SELECT contract_id
FROM transactions
WHERE sender_id = ?
GROUP BY contract_id, created_on DESC
Please do remember to escape your input values.
i have searched an answer for this but haven't figured out a proper solution. I have a database with one table 'data', where i have all products listed with their expiry dates. Total number of different products is somewhere around 120, but 'data'-table has over 5000 rows. Every product has multiple individual, expiry-monitored units.
I would need to list all unique products with columns for occurrences of expiry dates in each year. Currently i run multiple another queries for each year inside iteration of main query to count occurrences of expiry dates between two dates.
CREATE TABLE IF NOT EXISTS `data` (
`EXPIRY` date DEFAULT NULL,
`RNO` int(6) DEFAULT NULL,
`PRODID` int(3) DEFAULT NULL,
`NAME` varchar(38) DEFAULT NULL,
`RND` varchar(2) DEFAULT NULL,
`RDY` varchar(3) DEFAULT NULL,
`ARTY` varchar(3) DEFAULT NULL,
`ARYK` varchar(4) DEFAULT NULL,
`BATCH` varchar(16) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
// list all unique product rows
$main_loop = $database->query('SELECT * FROM data GROUP BY rno HAVING COUNT(*) >=1');
$rows = $database->resultset($main_loop);
foreach($rows as $data) {
echo "<tr>";
echo "<td>".$data['RNO']."</td>";
<td>
// another query to count occurrences of expiry in each product between two dates
$thisrno = $data['RNO'];
$database->query("SELECT * FROM data WHERE EXP BETWEEN '2016-01-01' AND '2016-12-31' AND RNO = '$thisrno'");
$database->execute();
$rows = $database->rowCount();
echo $rows;
echo "</td><td>";
...i would need to do this for each column (2016-2025)
...
}
I'd believe that there is better solution for this. Problem is also, that this way i cannot sort the table by the number of expiring units each year and this is not very efficient.
The result should be like:
RNO | NAME | Expiring in 2016 | Expiring in 2017 | ...
336540 | Prod_name_1 | 34 | 62 |
391755 | Prod_name_2 | 2 | 116 |
653112 | Prod_name_3 | 46 | 7 |
Seems fairly straightforward:
select rno, name,
sum(exp between '2016-01-01' and '2016-12-31') as exp2016,
sum(exp between '2017-01-01' and '2017-12-31') as exp2017,
sum(exp between '2018-01-01' and '2018-12-31') as exp2018,
sum(exp between '2019-01-01' and '2019-12-31') as exp2019,
sum(exp between '2020-01-01' and '2020-12-31') as exp2020,
sum(exp between '2021-01-01' and '2021-12-31') as exp2021,
sum(exp between '2022-01-01' and '2022-12-31') as exp2022,
sum(exp between '2023-01-01' and '2023-12-31') as exp2023,
sum(exp between '2024-01-01' and '2024-12-31') as exp2024,
sum(exp between '2025-01-01' and '2025-12-31') as exp2025
from data
where exp between '2016-01-01' and '2025-12-31'
group by rno;
If you want to include even products that have no expirations in those years, omit the where clause.
I'm not sure what your question is about sorting; you could pick one year and sort the rows by that year's counts of expirations, but that seems a little strange.
My problem:
Error: Duplicate entry '2' for key 'cnt_2'
My table:
CREATE TABLE UploadLog(
id int(11) NOT NULL AUTO_INCREMENT,
date text NOT NULL DEFAULT '',
cnt int(11) NOT NULL DEFAULT 0,
UNIQUE INDEX (id, cnt),
PRIMARY KEY (id)
)
My php code:
$date1=date("Y-m-d");
$sql = "SELECT * FROM UploadLog WHERE date='$date1'";
$result = $conn->query($sql);
$row = $result->fetch_assoc();
$dateindb=$row["cnt"];
if ($dateindb==0) {$dateindb=1;};
$sql = "INSERT INTO UploadLog (date, cnt) VALUES ('$date1', '$dateindb') ON DUPLICATE KEY UPDATE date=date, cnt=cnt+1";
if (mysqli_query($conn, $sql)) {} else {echo mysqli_error($conn)};
Data in MYSQL table:
+------+------------+-----+
| id | date | cnt |
+------+------------+-----+
| 1 | 2015-04-16 | 3 |
| 2 | 2015-04-17 | 2 |
| 3 | 2015-04-18 | 1 |
+------+------------+-----+
Current date = 2015-04-18.
Edited:
Command:
DESCRIBE DateLog
+-------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date | text | NO | | NULL | |
| cnt | int(11) | NO | UNI | 0 | |
+-------+---------+------+-----+---------+----------------+
Command:
SHOW CREATE TABLE UploadLog
UploadLog | CREATE TABLE `UploadLog` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` text NOT NULL,
`cnt` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
UNIQUE KEY `cnt_2` (`cnt`),
KEY `cnt` (`cnt`),
KEY `id_2` (`id`),
KEY `cnt_3` (`cnt`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
I cannot explain where the error come from, but I expect, it is caused by different MySQL versions.
But first off all I would recommend to change the date column from text to char(10). This is because the content have a very defined length.
After that the table definition will look like this:
CREATE TABLE DateLog
(
id INT(11) NOT NULL AUTO_INCREMENT,
date CHAR(10) NOT NULL,
cnt INT DEFAULT 0 NOT NULL,
UNIQUE INDEX (id, date, cnt),
PRIMARY KEY (id)
);
To get your code working you have just to add the id into the insert query. For that your code will change a little bit to:
$date1 = date("Y-m-d");
$sql = "SELECT * FROM DateLog WHERE date='$date1'";
$result = $conn->query($sql);
$row = $result->fetch_assoc();
// Check if entry for the current date already exists
if (null === $row) {
// If not, set id to NULL
$id = 'NULL';
$dateindb = 1;
} else {
// If it exist, use it
$id = $row["id"];
$dateindb = $row["cnt"];
}
// Insert with id
$sql = "INSERT INTO DateLog (id, date, cnt) VALUES ($id,'$date1', '$dateindb') ON DUPLICATE KEY UPDATE cnt=cnt+1";
if (mysqli_query($conn, $sql)) {
} else {
echo mysqli_error($conn);
}
To simplify the situation, there is no need for an auto increment primary key, because you can use the date column as one. From this it follows that you also don’t need an unique index, too.
So simply change your Table definition to:
CREATE TABLE DateLog
(
date CHAR(10) PRIMARY KEY NOT NULL,
cnt INT DEFAULT 1
);
After you can use the this to count the uploads:
$date1 = date("Y-m-d");
$sql = "INSERT INTO DateLog (date) VALUES ('$date1') ON DUPLICATE KEY UPDATE cnt=cnt+1";
if (mysqli_query($conn, $sql)) {
} else {
echo mysqli_error($conn);
}
Simple, or not?
Hope this helps.
The error is pretty obvious... you are trying to insert duplicate values in a column, defined as unique...
cnt=cnt+21 gives you 2, which you already have in your table.
The problem is the field cnt_2, which is UNIQUE. That means it can't have the same value for two different registers. You aren't setting it a value in the INSERT query, so it takes the default value, which already exist in another register.
I have written myself a PHP script to help manage a small squad of 10 members. This script current connects to a database and updates weekly updating any rank and power change. However I want to expand this and in a new table, have all the power gained kept in a separate column instead of adding it all up.
The only way I can think of doing this is by using the below code to create the column and changing the name for each.
ALTER TABLE `power gained` ADD timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP AFTER name;
So my question is, can I create columns making sure their name is unique, OR is it possible to set a column name to the timestamp as that would save me a column.
I'd like to also make it clear I am using mysql_ functions as this is on my local system, not vulnerable to attacks and I am not stupid enough to make mistakes.
Use normalisation.
Split the users and the power into two difference tables.
CREATE TABLE `users_power` (
`user_id` smallint(5) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`total_power` int(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
CREATE TABLE `power` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` smallint(1) NOT NULL,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`power_increase` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
DROP TRIGGER IF EXISTS `Update users_power`;
CREATE TRIGGER `Update users_power` AFTER INSERT ON `power` FOR EACH ROW BEGIN
UPDATE `users_power` AS `UP`
SET `UP`.`total_power` = `UP`.`total_power` + NEW.`power_increase`
WHERE `UP`.`user_id` = NEW.`user_id`;
END
And then to look up, do something like;
SELECT `power` AS total_power
FROM users_power
WHERE users_power.`user_id` = 1
And your structure would look something like;
select * from power where user_id = 1;
+----+---------+---------------------+----------------+
| id | user_id | time | power_increase |
+----+---------+---------------------+----------------+
| 1 | 1 | 2014-08-7 17:04:06 | 5 |
| 2 | 1 | 2014-08-15 17:04:31 | 15 |
+----+---------+---------------------+----------------+
2 rows in set
select * from users_power where user_id = 1;
+---------+------+-------------+
| user_id | name | total_power |
+---------+------+-------------+
| 1 | joe | 21 |
+---------+------+-------------+
1 row in set
Edits
Added trigger to automatically update total power when a record is inserted into power
Haven't yet tested this but I think I have found a way I can do this in a way that I understand (which is the most important part).
$now = date('Y-m-d');
mysql_query("ALTER TABLE `power gained` ADD `$now` VARCHAR(22) AFTER name");
// ...
mysql_query("UPDATE `power gained` (`$now`) VALUES($gained) WHERE id = $i");
I'm not looking to extract the data from the database as I can access it just by going to localhost/phpmyadmin and I'm not going to ever need to extract it.