Group results by same column value - php

Im trying the following:
I have a model (HbwerllMargins) with the following fields:
id| userId | clinicId | payMethodId | percentage | createdTime | updatedTime | deletedTime
Im trying the following query:
$hbwellMargins = HbwellMargins::find()->andWhere(['clinicId' => $id])->all();
Where result is associated to a certain clinicId value, but what I need is also to group the result by the same userId values without specifying a value.
For example, for clinicId=1, userId = 1 has 6 registers, userId = 2, has 1 register, etc
Im trying to find out in ActiveQuery Documentation but I havent found yet a solution...what I would need to do that? Is there any way to do that?
Thans a lot for your help!!

You can group the result by the same userId values like this:
If you just want to fetch all records and group the results:
$hbwellMargins = HbwellMargins::find()->orderBy('userId')->all();
If you want to fetch results with your condition and group the results:
$hbwellMargins = HbwellMargins::find()->where(['clinicId' => $id])->orderBy('userId')->all();

Related

Grouping and counting results based on column PHP Mysql

I have a table recording hits to pages like this :
id | ip_address | page_id
---------------------------------------
1 | 192.123.456.78 | 2787321
2 | 192.000.000.00 | 2787321
3 | 192.123.456.78 | 342415
4 | 192.123.456.78 | 2787321
5 | 192.432.999.80 | 2787321
I'm getting the results like this :
$getHits = $wpdb->get_results( "SELECT * FROM $table WHERE page_id = $pageID" );
I want to display the results grouped by ip_address based on how many times each IP accessed the same page_id.
Example of desired output (where $pageID = 2787321) :
192.123.456.78 - 2 Views
192.000.000.00 - 1 View
192.432.999.80 - 1 View
I've been trying a few things (grouping mainly and running through while and foreach loops) but it quickly got really complicated and I can't get it to work.
Could somebody point me in the right direction please?
You should not use var for dinamic query you are at risk of sqlinjection
anyway
$wpdb->get_results( "SELECT ip_address, count(*) hits
FROM $table WHERE page_id = $pageID
GROUP BY ip_address
ORDER BY hits DESC" );
http://www.mysqltutorial.org/mysql-group-by.aspx

Yii2: ActiveRecord with distinct query

I need to write an ActiveRecord query where I get all fields of rows without duplicates in one field.
Example: Here is a table of books. I want to get all data of the rows with
distinct isbn. From duplicates the first row should be taken. The result should be the rows with id 1,2,4
id | title | isbn
--- | ------- | ------
1 | hello | 1001
2 | world | 1002
3 | this | 1002
4 | is | 1003
5 | funny | 1003
My first attempt was
$books = Books::find()->select('isbn')->distinct()->all();
but that fills only the isbn field in $books[0], $books[1], ....
Is this possible using Yii2 ActiveRecord?
You may use groupBy() for this:
$books = Books::find()->groupBy(['isbn'])->all();
But this returns random row with matching isbn value and may not work in some DBMS. Your requirements are too ambiguous to handle it in predictable way. But if you want always first row, you may use subquery to fetch matching isbn and id:
$query = (new Query())
->select(['MIN(id) as id, isbn'])
->from(Books::tableName())
->groupBy(['isbn']);
return Books::find()
->alias('book')
->innerJoin(['subquery' => $query], 'book.id = subquery.id AND book.id = subquery.id')
->all();
The description given in Yii2 for the distinct property is as follows:
Whether to select distinct rows of data only. If this is set true, the SELECT clause would be changed to SELECT DISTINCT.
-- https://www.yiiframework.com/doc/api/2.0/yii-db-query#$distinct-detail
therefore you should pass true with distinct property if you need to select the distinct values of 'isbn' as follows:
$books = Books::find()->select('isbn')->distinct(true)->all();

sum all row from 2 column and use select to display two column

example
|like |comment|
|user1|asd |
|user2|awe |
|user3|aqw |
|user4|atr |
|user5|axc |
|user6|azw |
|user7| |
i have two column and what i wanted to do is to sum all rows inside those column and fetch the two column but i dont have any idea on how to do it in a query in sql.
result
|like |comment|
| 7 | 6 |
i tried queering it but i can only fetch 1 column i dont know how to do it with two column..
function countpostcomment($puid){
$sql = "SELECT COUNT(pc_comment) FROM pcomment WHERE post_uid = '$puid'";
$stmt = $this->dbh->prepare($sql);
$stmt->execute(array("0"));
$active_data = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $active_data;
}
here is my sample query i haven't tested the whole function only the select cause i dont know if i need to use array or not..
I think you simply want:
SELECT COUNT(*) as likes, COUNT(pc_comment) as comments
FROM pcomment
WHERE post_uid = '$puid';
COUNT(*) counts the number of rows (7 in this case). COUNT(<column name>) counts the number of non-NULL values in the column (6 in this case).

Getting an array as a field from result row

I'm pretty new to databases, so my question is:
Let's say that we have two tables: Users and Orders
Is it possible (and how do I do it) to list all users with their data (First & Last name, birthdate etc) and associated orders in one query? So the result should look something like this:
|------------------------------|
| John Doe | Order 1 details |
| | Order 2 details |
| | Order 3 details |
|------------------------------|
| Janny Hoe | Order x details |
| | Order y details |
|------------------------------|
So you got the point? Each row from table1 has a field which contains multiple rows from table2? I've heard MySQL doesn't return multidimensional arrays, so how does it return something like this?
Any help would be greatly appreciated!
EDIT:
Table structure could be something like this:
TABLE users:
id | name
TABLE orders:
id | user_id | date_ordered | other unrelevant data...
I know this is doable with joins, but what bugs me is what will it return?
Will result have field orders which would be array containing orders row data like $result[0]['orders'][0]['date_ordered'] or something like that ?
Do a LEFT join (if there is a possibility that a user does not have any orders) and then gather the results in an array, based on the user ID:
SELECT Users.id, Users.name, Order.detail
FROM Users
LEFT JOIN Order
ON Users.id= Order.user;
Ex:
$userOrders = array();
$sql = 'SELECT Users.id, Users.name, Order.detail
FROM Users
LEFT JOIN Order
ON Users.id= Order.user';
foreach ($pdo->query($sql) as $row) {
$userOrders[$row['user_id']][] = $row;
}

Querying a MySQL database to show a selected row and ALL rows

I have a problem at the moment where I'm trying to get all rows plus a selected row from my tables.
So I have three tables - users, tasks, and a joining table called tasks_users
The latter table just contains two columns - task_id and user_id, for the purpose of normalization.
I have a form to edit a task. The problem arises when I want to retrieve ALL users (so the task can be reassigned) and I also want to show the CURRENT user. Given my current queries I can only get all the users, or just the single related user.
Am I overlooking something obvious, or do I need a more complex query? Or perhaps a couple of queries?
Further clarification:
Imagine you have an "edit task" form and on it you have the user currently assigned. I want to also show all other users, so that I may reassign. Given that I have three tables I'm struggling to construct a query that returns what I want. Currently I can only return ALL user OR the single assigned user.
It seems it's not about the current user, but the task assignee. No matter who assigns the task, he should not be able to assign it to the current assignee.
If only one user can be assigned to a particular task, you can remove task_users table, because simply adding column user_id in table tasks will do the same job.
Let's say you have in table users
id | username |
---------------------
1 | A |
2 | B |
3 | C |
4 | X |
5 | Y |
And in table tasks
id | title | user_id |
-----------------------------------
1 | Bla | 3 |
2 | Asd | NULL | // if this is even possible
If you want to retrieve who you can assign to task_id = 1 (Bla), you can simply do:
$currentTaskID = 1; // or however you retrieve them, it's just for the explanation purpose
SELECT id, username FROM users WHERE id != (SELECT user_id FROM tasks WHERE id = $currentTaskID);
The output will be:
id | username |
---------------------
1 | A |
2 | B |
4 | X |
5 | Y |
If a task can be assigned to more than one user, and you will keep task_users table, we can imagine you have there:
task_id | user_id |
-------------------------
1 | 3 |
2 | NULL |
1 | 5 |
You can query this way:
$currentTaskID = 1; // or however you retrieve them, it's just for the explanation purpose
SELECT id, username FROM users WHERE id NOT IN (SELECT user_id FROM task_users WHERE task_id = $currentTaskID);
So the output will be:
id | username |
---------------------
1 | A |
2 | B |
4 | X |
If you permit NULL values in assignee, so a task is not assigned to anyone, the SELECT will return all users, because of WHERE id != NULL when you have no NULL id's in users
For the purpose of showing the current user somewhere, but not available for assigning, you should separate the queries in functions/methods.
Saying you have:
function getAvailableAssignees($task_id) {
$sql = "SELECT id, username FROM users WHERE id != (SELECT user_id FROM tasks WHERE id = $task_id);";
$this->query($sql);
return $this->result();
}
and
function getCurrentAssignee($task_id) {
$sql = "SELECT user_id FROM tasks where id = $task_id;";
$this->query($sql);
return $this->result();
}
So once you need to show the available assignees, you call the respective method, so do, when you need to show the current assignee.
I think you might be looking for a UNION ALL
SELECT username, status from table
UNION ALL
SELECT username, status from table where status = 'current' LIMIT 1
Make sure that amount of columns from first query matches the amount of columns from second query. Don't do SELECT * FROM in one query and SELECT username from in another.
I think you should do 2 queries, not 1.. It doesn't seem like the users table should be in the same data selection as the tasks and users selection.
If you insist on combining the results you can do use UNION DISTINCT to combine the results of 2 queries.
THe first query decides the columns to be returned so you should set it to be the joined tables since those are more columns. The users should also fit in the columns of the joined select since it already contains them.
Thank you for all the replies. I have however managed to fix the issue using a nested foreach loop:
<ul>
<?php foreach($stages as $stage):?>
<li>
<label>
<?php echo $stage['stage_id']; ?>
<input type="checkbox" name="stages[]" value="<?php echo $stage['stage_id']; ?>"
<?php
// loop through the assigned stages. if it matches the stage ID then echo checked
foreach ($assigned_stages as $assigned_stage)
{
if ($stage['stage_id'] === $assigned_stage['stage_id'])
{
echo 'checked';
}
}
?>
/>
<?php echo $stage['name']; ?>
</label>
</li>
<?php endforeach; ?>
</ul>
This is a very common case and I'm still unsure if this is the best approach, however it works without issue and there isn't a great deal of code involved, so for the time being I'm happy.

Categories