i have a Collection like that:
+----------+----------+
| user_id | city_id |
+----------+----------+
| 1 | 1 |
| 2 | 1 |
| ... | ... |
| 901 | 2 |
| 902 | 2 |
| ... | ... |
| 1501 | 3 |
| 1502 | 3 |
| ... | ... |
+----------+----------+
in this example i have
900 users for city_id = 1
600 users for city_id = 2
300 users for city_id = 3
what i want to do:
Sort each user in a fair way, so that I end up with a list like this:
+---------+----------+
| user_id | city_id |
+---------+----------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 901 | 2 |
| 902 | 2 |
| 1501 | 3 |
| 4 | 1 |
| 5 | 1 |
| 6 | 1 |
| 903 | 2 |
| 904 | 2 |
| 1502 | 3 |
+---------+----------+
I divided everything by 300 (for example), so i have by day:
3 users from city 1
then 2 users from city 2
then 1 user from city 3
then 3 users from city 1
then 2 users from city 2
then 1 user from city 3
...
I tried to use the take() function but it doesnt modify the original collection.
And i used the shift() function but it just take one item.
i tried that code:
while($users->isNotEmpty()){
// $user->count() = 1800
for ($i=0; $i<3; $i++){
$final->push($users->where('city_id', 1)->shift());
}
for ($i=0; $i<2; $i++){
$final->push($users->where('city_id', 2)->shift());
}
$final->push($users->where('city_id', 3)->shift());
// $user->count() = 1800; $final->count() = 6
}
it doesn't shift element from $user collection. still have 1800 elements...
Thanks !
Related
I have 3 tables: shows, seasons and ratings. I would like to get average ratings of specific seasons and then make an average of this for every show and sort them by this value asc or desc. I was able to get this result by this raw query:
$shows = Show::selectRaw('shows.*, avg(x.seasons_avg_points) as ratings_avg_points')
->fromSub(function($query){
$query->selectRaw('shows.id, avg(ratings.points) as seasons_avg_points')
->from('shows')
->join('seasons', 'shows.id', '=', 'seasons.show_id')
->leftJoin('ratings', 'ratings.item_id', '=', 'seasons.item_id')
->groupBy('seasons.id');
}, 'x')
->join('shows', 'shows.id', '=', 'x.id')
->groupBy('x.id')
->get()->sortBy('shows_avg_points');
However I prefer to use Laravel eloquent functions so I tried also this:
$shows = Show::with(['seasons' => function($query){
$query->withAvg('ratings', 'points');
}])->withAvg('seasons', 'ratings_avg_points')->get();
Unfortunately, it only works without ->withAvg('seasons', 'ratings_avg_points'), as there can't be made an average of a computed column (ratings_avg_points) and it can't be found.
shows
| id | name |
|----|--------|
| 1 | show 1 |
| 2 | show 2 |
| 3 | show 3 |
seasons
| id | show_id | item_id | name |
|----|---------|---------|----------|
| 1 | 1 | 1 | season 1 |
| 2 | 1 | 2 | season 2 |
| 3 | 2 | 3 | season 1 |
| 4 | 2 | 4 | season 2 |
| 5 | 3 | 5 | season 1 |
| 6 | 3 | 6 | season 2 |
ratings
| id | item_id | points |
|----|---------|--------|
| 1 | 1 | 0 |
| 2 | 1 | 20 |
| 3 | 2 | 0 |
| 4 | 2 | 30 |
| 5 | 3 | 0 |
| 6 | 3 | 40 |
| 7 | 4 | 0 |
| 8 | 4 | 50 |
| 9 | 5 | 0 |
| 10 | 5 | 60 |
| 11 | 6 | 0 |
| 12 | 6 | 70 |
result
| id | name | ratings_avg_points|
|----|--------|-------------------|
| 3 | show 3 | 32.5 |
| 2 | show 2 | 22.5 |
| 1 | show 1 | 12.5 |
Is there a way I can get Show models with their average rating values without using that 'ugly' query above?
I want to concatenate and count data of the same column, so I can concatenate but I can not count the repeated data.
Here's my table of data:
| ID | bills | class |
|-----|-------|-------|
| 1 | 0.5 | 2 |
| 2 | 1 | 1 |
| 3 | 0.5 | 2 |
| 5 | 1 | 3 |
| 6 | 0 | 2 |
| 7 | 0.5 | 1 |
| 8 | 1 | 2 |
| 9 | 1 | 3 |
| 10 | 0.5 | 1 |
| 11 | 0 | 2 |
| 12 | 1 | 1 |
| 13 | 0 | 3 |
| 14 | 1 | 2 |
| 15 | 0 | 1 |
| 16 | 0 | 1 |
| 17 | 0.5 | 3 |
| 18 | 0 | 3 |
| 13 | 0.5 | 3 |
Here's my sql query I'm using to concatenate data:
SELECT class AS lesson,
GROUP_CONCAT( bills ORDER BY bills ) AS bills
FROM tb_presence
GROUP BY class;
Here's my result below:
| class | bills |
|-------|------------------|
| 1 | 1,0.5,0.5,1,0,0 |
| 2 | 0.5,0,1,0,1 |
| 3 | 1,1,0,0.5,0,0.5 |
Now I would like to count the data that are equal, but continue with the same concatenation.
I want to "count" the data with the same values and display concatenated (column observation and only to help understanding)
| class | bills | observation |
|-------|-------|-----------------------------|
| 1 | 2,2,2 | (2=0+0) (2=0.5+0.5) (2=1+1) |
| 2 | 2,1,2 | (2=0+0) (1=0.5) (2=1+1) |
| 3 | 2,2,2 | (2=0+0) (2=0.5+0.5) (2=1+1) |
Is this really possible?
Here is a solution (thanks to #wchiquito for the sqlfiddle) See http://sqlfiddle.com/#!2/2d2c8/1
As you can see it cannot dynamically determine the bills' values and count them. But there is a count per bill value that you want.
SELECT class AS lesson,
GROUP_CONCAT( bills ORDER BY bills ) AS bills
,SUM(IF(bills=0,1,0)) AS Count0
,SUM(IF(bills=0.5,1,0)) AS Count05
,SUM(IF(bills=1,1,0)) AS Count1
,COUNT(*) AS totalRecords
,COUNT(*)
- SUM(IF(bills=0,1,0))
- SUM(IF(bills=0.5,1,0))
- SUM(IF(bills=1,1,0))
AS Missing
FROM tb_presence GROUP BY class;
I added an extra record to show how the 'missing' column could show if you were not taking all values into consideration.
Results
| LESSON | BILLS | COUNT0 | COUNT05 | COUNT1 | TOTALRECORDS | MISSING |
|--------|-----------------------------------------|--------|---------|--------|--------------|---------|
| 1 | 0.00,0.00,0.50,0.50,1.00,1.00,1.00,4.00 | 2 | 2 | 3 | 8 | 1 |
| 2 | 0.00,0.00,0.50,0.50,1.00,1.00 | 2 | 2 | 2 | 6 | 0 |
| 3 | 0.00,0.00,0.50,0.50,1.00,1.00 | 2 | 2 | 2 | 6 | 0 |
I want to display dynamic mysql vertical data to horizontal in html table using PHP. And my table is like
mysql> select * from role_perm;
-------------------------------------------
| id | userID | roleID | permID | value |
--------------- ---------------------------
| 1 | 2 | 1 | 1 | 1 |
|------------------------------------------
| 2 | 2 | 1 | 2 | 0 |
|------------------------------------------
| 3 | 2 | 1 | 3 | 0 |
|------------------------------------------
| 4 | 2 | 2 | 4 | 0 |
-------------------------------------------
| 5 | 2 | 2 | 1 | 1 |
|------------------------------------------
| 6 | 2 | 2 | 2 | 1 |
|------------------------------------------
| 7 | 2 | 2 | 3 | 0 |
|------------------------------------------
| 8 | 2 | 2 | 4 | 1 |
-------------------------------------------
| 9 | 5 | 1 | 1 | 1 |
|------------------------------------------
| 10 | 5 | 1 | 2 | 0 |
|------------------------------------------
| 11 | 5 | 1 | 3 | 0 |
|------------------------------------------
| 12 | 5 | 1 | 4 | 0 |
-------------------------------------------
and so on...
and i want to display in html table like
----------------------------
| role | permissions |
----------------------------
| 1 | 1 | 2 | 3 | 4 |
----------------------------
| 2 | 1 | 2 | 3 | 4 |
----------------------------
| 3 | 1 | 2 | 3 | 4 |
-----------------------------
| 4 | 1 | 2 | 3 | 4 |
----------------------------
could you pls help me. Thank you in advance.
Try this:
SELECT
roleID AS role,
GROUP_CONCAT(DISTINCT permID ORDER BY permID ASC SEPARATOR '|') AS permissions
FROM role_perm
GROUP BY roleID
ORDER BY roleID
I suppose you could do this with a nifty MySQL query as well (which would supposedly be better for performance), but since I'm not that good at SQL, here's the PHP solution:
$arrRoles = array();
while ($row = mysql_fetch_assoc($result)) {
if (!isset($arrRoles[$row['roleID']])) {
$arrRoles[$row['roleID']] = array();
}
$arrRoles[$row['roleID']][$row['permID']] = $row['value'];
}
var_dump($arrRoles);
I have a database table campaign_data. I need to select the customer_id where in the campaign there is difference in tariff. How can i do that with MySQL query. Here is some sample data.
SQL Fiddle Schema
| CAMPAIGN_ID | CUSTOMER_ID | CAMPAIGN_NAME | TARIFF |
---------------------------------------------------------
| 1 | 1 | Richmond | 100 |
| 2 | 1 | Sutton Coldfield | 75 |
| 3 | 1 | Putney | 100 |
| 4 | 1 | Kentish Town | 100 |
| 5 | 1 | Woking | 100 |
| 6 | 2 | Chiswick | 90 |
| 7 | 2 | Ealing | 100 |
| 8 | 2 | Camden | 100 |
| 9 | 3 | Croydon | 75 |
| 10 | 3 | Croydon1 | 100 |
| 11 | 3 | Archway | 100 |
| 12 | 4 | Ealing0 | 100 |
| 13 | 4 | Ealing01 | 100 |
| 14 | 4 | Ealing02 | 100 |
| 15 | 4 | Chingford | 100 |
| 16 | 4 | chingford01 | 100 |
Now as you can see customer id 1 , and 3 has different tariffs. I want to select them and leave the customer id 4 because it has campaigns with same tariffs.
Desired Output
| CUSTOMER_ID |
---------------
| 1 |
| 2 |
| 3 |
For clearification you can see customer 1 has 5 records. If in his 5 records the tariff is same (100) i want to avoid but if the tariff is not some as 4 records have 100 and one has 75, i want to select.
SELECT customer_id, count(DISTINCT tariff) as tariffs
FROM campaign_data
GROUP BY customer_id
HAVING tariffs > 1
you looking for this maybe
SELECT customer_id
FROM campaign_data
GROUP BY customer_id
HAVING count(DISTINCT tariff) > 1
http://sqlfiddle.com/#!2/48b6e/31
select
customer_id,
tariff
from campaign_data
group by customer_id
having sum(tariff)/count(tariff) <> tariff;
DATABASE Structure:
ID | USERID | ENTRYDATE | EXITDATE | PRICE | ROOMID
-----------------------------------------------------
1 | 2 | 2012-10-1 | 2012-10-4| 100 | 1
2 | 2 | 2012-10-1 | 2012-10-4| 100 | 2
3 | 2 | 2012-10-1 | 2012-10-4| 100 | 3
4 | 2 | 2012-10-6 | 2012-10-9| 100 | 4
5 | 2 | 2012-10-6 | 2012-10-9| 100 | 55
i need some help please. I want to display a set of records from this database. i want to display all those with same USERID, but group those with the same ENTRYDATE and EXITDATE in the same DIV. example, the result should be like this...
ID | USERID | ENTRYDATE | EXITDATE | PRICE | ROOMID
------------------------------------------------------
1 | 2 | 2012-10-1 | 2012-10-4| 100 | 1
2 | 2 | 2012-10-1 | 2012-10-4| 100 | 2
3 | 2 | 2012-10-1 | 2012-10-4| 100 | 3
ID | USERID | ENTRYDATE | EXITDATE | PRICE | ROOMID
----------------------------------------------------
4 | 2 | 2012-10-6 | 2012-10-9| 100 | 4
5 | 2 | 2012-10-6 | 2012-10-9| 100 | 5
I am not sure I understand your question correctly. I assume you have a string-indexed array and you want to split it basing on ENTRYDATE and EXITDATE values. Maybe something like this:
$currentEntry = $data[0]['ENTRYDATE'];
$currentExit = $data[0]['EXITDATE'];
$splitted = array();
$i = 0;
foreach ($data as $row) {
if ($row['ENTRYDATE'] == $currentEntry && $row['ENTRYDATE'] == $currentExit) {
$splitted[$i] []= $row;
} else {
$currentEntry = $row['ENTRYDATE'];
$currentExit = $row['EXITDATE'];
$i++;
}
}