$query = "SELECT COUNT(id) FROM complaint WHERE ID_complntCategory = ?";
$complntCategory = $database->prepare($query);
try {
$complntCategory->execute(array());
$complntCategory->setFetchMode(PDO::FETCH_ASSOC);
foreach ($complntCategory as $key) {
$totaalM = $key['1'];
$totaalV = $key['2'];
$totaalG = $key['3'];
}
}
catch(PDOException $e) {
echo "Error";
}
Above you see my PHP code, and here is what I'm trying to do:
I'm trying to get the amount of rows from the table 'complaint' into 3 different variables (totaalM, totaalV and totaalG). The totaalM variable should contain the amount of rows 'WHERE ID_complntCategory = 1'.
For the other variables the 'ID_complntCategory' should be 2 and 3
('ID_complntCategory' is either 1, 2 or 3)
There should be a way where I don't have to write 3 queries, right?
I'm clearly approaching this the wrong way, and I'm not sure how I should tackle this problem...
What you are trying to do is called pivot rows into columns, but MySQL doesn't have pivot table operator like other RDBMS, but you cane use the case expression like this in one query:
SELECT
SUM(CASE WHEN ID_complntCategory = 1 THEN 1 ELSE 0 END) AS totaalM,
SUM(CASE WHEN ID_complntCategory = 2 THEN 1 ELSE 0 END) AS totaalV,
SUM(CASE WHEN ID_complntCategory = 3 THEN 1 ELSE 0 END) AS totaalG,
COUNT(Id) AS Total
FROM complaint;
Or you can make it shorter like this:
SELECT
SUM(ID_complntCategory = 1) AS totaalM,
SUM(ID_complntCategory = 2) AS totaalV,
SUM(ID_complntCategory = 3) AS totaalG,
COUNT(Id) AS Total
FROM complaint;
Demo
This will give you something like this:
| totaalM | totaalV | totaalG | Total |
|---------|---------|---------|-------|
| 2 | 3 | 1 | 7 |
Here you need some magic, involving special SQL and PDO features.
First, you need an SQL query that is giving you desired results in one query. To get that you need a GROUP BY operator:
SELECT ID_complntCategory, count(*) FROM complaint GROUP BY ID_complntCategory
it will give you counts split by ID_complntCategory.
Next, you can use one of PDO's magnificent features, PDO::FETCH_KEY_PAIR fetch mode, that will give you an array where key would be category id and value is count
$sql = "SELECT ID_complntCategory, count(*) FROM complaint GROUP BY ID_complntCategory";
$stmt = $database->prepare($sql);
$key = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
$totaalM = $key['1'];
$totaalV = $key['2'];
$totaalG = $key['3'];
note that you should never catch a PDO errors only to say "error". Let PHP error reporting to do it instead.
Related
QUERY:
SELECT month(date_created), count(a.ticket_num)
FROM ticket as a
LEFT JOIN user_management as b on b.engineer_id = a.ticket_engineer
WHERE b.tl_id = 'sample_id'
AND year(date_created) = '2019'
GROUP BY extract(year from date_created), extract(month from date_created)
SAMPLE OUTPUT:
month | ticket_num
----------------------
2 | 12
4 | 24
6 | 78
EXPECTED SAMPLE OUTPUT:
month | ticket_num
----------------------
1 | 0
2 | 12
3 | 0
4 | 24
5 | 0
6 | 78
As you can see the above expected output, i'm trying to place all existing month in the first column and set all the count to zero if not existed in the second column. As of now, i only have the query for sorting the ticket count by month that is existed when the ticket is created.
There are different approaches to this problem. One is pure SQL for example.
But I would say a PHP based solution is simpler. Basically you need to get your data into array, then create a loop that outputs the desired months order, and have a condition that sees whether we have a corresponding row in our array and outputs ether the actual data or a zero accordingly.
The only tricky part is to have such an array that would let us check the data availability. For this we have to index it with month numbers. Not a big deal actually
$sql = "SELECT month(date_created), count(a.ticket_num) ...";
$res = $mysqli($sql);
$data = [];
while($row = mysqli_fetch_row($res)) {
$data[$row[0]] = $row[1];
}
Now $data is an array indexed by the month number. The rest is a primitive loop
foreach (range(1,12) as $month) {
echo $data[$month] ?: 0;
}
On a side note I would like to advertise using PDO as opposed to mysqli for your database interactions as this case clearly displays the superiority of the former. Using PDO we can get the indexed array right away, without an explicit loop, thanks to a special fetch mode:
$sql = "SELECT month(date_created), count(a.ticket_num) ...";
$data = $data = $pdo->query($sql)->fetchAll(PDO::FETCH_KEY_PAIR);
That's all!
I have a table like so:
User_Id Column1 Column2 Column3
1 Yes No Yes
2
I want to use mysql query to list all the column names (there are more than 3) which match the User_Id '1' and have a value of 'Yes'.
I get an error:
Trying to get property 'num_rows' of non-object
Here is what I have tried:
<?php $myStats = $mysqli->query("SELECT COLUMN_NAME FROM user_services.columns WHERE myColumn = 'Yes'");
if ($myStats->num_rows > 0) {
// output data of each row
while($row = $myStats->fetch_assoc()) {
$rows[] = $row; }
return $rows; ?>
Please can someone show me where I am going wrong?
Thanks in advance.
The CONCAT_WS function comes in handy here:
SELECT CONCAT_WS(',', IF(Column1='Yes', 'Column1', NULL),
IF(Column2='Yes', 'Column2', NULL),
IF(Column3='Yes', 'Column3', NULL)) AS columns
FROM user_services.columns
WHERE User_Id = 1;
If you have more than 3 columns, then you may add more terms to above CONCAT_WS call. Your problem mainly seems to be a SQL one, so I won't add any PHP code.
Note that your design might be better off if your column strings were spread across rows, rather than columns. For instance, consider the following alternative:
User_Id | number | val
1 | 1 | Yes
1 | 2 | No
1 | 3 | Yes
Then, if you wanted all column numbers which were yes for user 1, you could simply do:
SELECT
User_Id,
GROUP_CONCAT(number ORDER BY number) columns
FROM yourTable
WHERE
User_Id = 1
GROUP BY
User_Id;
My db is structured like:
id | posts | groups
----+--------+-----------
1 | 10 | 2
2 | 30 | 2
3 | 20 | 2
4 | 50 | 2,8
5 | 54 | 2,8
When a user gets to 50 or more posts I want the script to remove the group '2'. There is already a prior script that adds the '8'.
I have this:
$cusstring = mysql_query("SELECT `groups` FROM `users` WHERE `postnum` >= 50 ");
$row = mysql_fetch_array($cusstring);
$array = explode(',', $row[groups]);
$pos = array_search('2', $array);
unset($array[$pos]);
$row[groups] = implode(',', $array);
mysql_query("UPDATE `users` SET `groups` = $row[groups] WHERE `postnum` >= 50 ");
It just doesn't seem to update though. I don't know if this is because it picks up multiple fields in the array or if I'm doing something wrong with the greater than or equal to symbol.
Can anyone offer a solution?
Thanks.
EDIT:
I've worked out that if I change the symbol to equal to the query works on the first row it comes across with a post count of 50 but it leaves the rest. It would appear it's only able to process one row.
I think this would work for you. I think a SQL approach would be more efficient but you've said you want to keep it in PHP.
$cusstring = mysql_query("SELECT `groups`, `id ` FROM `users` WHERE `postnum` >= 50 ");
while($row = mysql_fetch_array($cusstring)) {
$groups = mysql_real_escape_string(preg_replace('~(^|\s+)2(,|$)~', '', $row['groups']));
//regex demo https://regex101.com/r/eX7qD1/1
$id = (int)$row['id'];
mysql_query("UPDATE `users` SET `groups` = '$groups' WHERE `id ` = $id ");
}
Your code is only getting one record because you aren't looping the fetch.
Also don't put data that comes from your DB back into a query directly this can lead to a SQL injection. Note I cast the ID here to an int and escaped the groups value. This should prevent the possibility of an injection.
You should switch drivers to PDO or MYSQLI. Once using one of those drivers you can use prepared statements.
This solution also will put an empty value in the groups field if 2 was the only value.
I am attempting to create an end-user page where I present different servers that are available to check-out. A server at any given time can have either an "Available" status or a "Reserved" status. I'm using a MySQL backend. This is how I am doing my query:
SELECT *, COUNT(CASE WHEN Status = 'Available' THEN 1 ELSE NULL END) AS Amount
FROM products GROUP BY id
This is the result I get:
id,Server_Type,Status,Amount
1,BL460,Available,1
2,BL460,Available,1
3,BL460,Reserved,0
4,BL460,Reserved,0
5,BL460,Reserved,0
6,DL360,Available,1
7,DL360,Reserved,0
8,DL360,Reserved,0
Where Reserved is equal to 0, and Available is equal to 1. I only want the end-user to be able to checkout a server in Available status.
To the question: What I want to do in the page is present the list of servers on the page in this way, where Available is equal to the amount:
BL460 - Amount: 2
DL360 - Amount: 1
How can I achieve this format in PHP?
Another option is a crosstab query -
SELECT `Status`,
SUM(IF(`Server_Type` = 'BL460' AND `Status` = 'Available', `Amount`, 0)) AS `BL460`,
SUM(IF(`Server_Type` = 'DL360' AND `Status` = 'Available', `Amount`, 0)) AS `DL360`
FROM `products`
GROUP BY `Status`
Your table would look like this -
Status | BL460 | DL360 |
Available | 2 | 1 |
Reserved | 0 | 0 |
Here is an EXAMPLE
Even better would be to flip things around -
SELECT `server_type`,
SUM(IF(`status` = 'Available', 1, 0)) AS `Available`,
SUM(IF(`status` = 'Reserved', 1, 0)) AS `Reserved`
FROM `servers`
GROUP BY `server_type`;
Which would result in a table that looks like this (based on data in the fiddle) -
server_type | Available | Reserved
BL460 | 3 | 1
DL360 | 1 | 2
Here is that EXAMPLE
Here I could continue to add servers to the table without having to worry about adding them to the query as you would have to do in the first query. If you add an additional status you would have to change the query.
Note in both cases there is no need for an Amount column as the status is the item counted. By placing the load on the database server it makes it much easier to output the HTML as you are just going row bu row as you normally would.
Well, that would probably be easier if you do it directly in your SQL query:
SELECT Server_Type, COUNT(*) AS Count FROM products WHERE Status = 'Available' GROUP BY Server_Type
This should give you exactly the table you want.
If you want to do it in PHP, the easiest solution would probably be to loop through your SQL result and count the number of available servers per Server_Type in an associative array where the Server_Type is your array key:
$amounts = array();
foreach($sql_result as $entry) {
if($entry['Amount'] == 1) {
if(isset($amounts[$entry['Server_Type']])) {
$amounts[$entry['Server_Type']]++;
} else {
$amounts[$entry['Server_Type']] = 1;
}
}
}
echo $amounts;
Edit: in order to print the values as described in the question, you could use the following code snippet:
foreach($amounts as $name=>$amount) {
echo $name + " - Amount: " + $amount + "<br>";
}
I have 2 tables for my articles in DB:
articles
tags
tags table structure and current state:
primary key for my tags table is tag column.
tag | post_ids | count |
-------------------------------------
a | 2,0 | |
b | 1,2,0,0 | |
tag1 | 1,2,0,0 | |
j | 2,0 | |
I want to update count column after any INSERT (new post) or UPDATE (existing post) action and I want to do it with prepared statements.
For the time being, I can dynamically construct the input: $array = array("2","4","4","2") which is the related values of the count column to be updated.
And with the code below; I tried to update the count column however count always updates with value = 2 for all count rows.
I have no warning/error.
MySQL version: 5.5
I have to update 1st count row with the $array[0], 2nd count row with the $array[1] ... So I have to utilize LIMIT, OFFSET arguments
I learnt that MySQL doesn't allow OFFSET in UPDATE queries
I am not capable to write complex queries, I searched SO and found the Q&A: LIMIT offset or OFFSET in an UPDATE SQL query
It seemed to me the sql I used from that Q&A is logically suitable for my case however I didn't understand the sql.
I am not 100% sure that problematic area is the sql.
I want to correct my code and learn why it fails?
Can you please help?
Best regards
MY CODE
$query = "UPDATE tags SET count = ?
WHERE tag IN(SELECT tag FROM (SELECT tag FROM tags LIMIT ?,1) as u)";
$stmt = $mysqli->prepare($query);
if($stmt === false)
{
trigger_error('SQL Error: ' . $mysqli->error, E_USER_ERROR);
}
$stmt->bind_param("ii", $count, $i);
$i = 0;
foreach ($array as $a) // $array: related values of the `count` column to be updated
{
$count = intval($a);
$stmt->execute();
$i = $i + 1;
}
$stmt->close();