This question already has an answer here:
Ranking the results in mysql (mysql equivalents for 'dense_rank()' or 'row_number()' functions in oracle)
(1 answer)
Closed 4 years ago.
This is my table data
prod_id category_id
1 1
2 2
3 2
4 3
5 3
6 3
Expected result
prod_id category_id seq_no
1 1 1
2 2 1
3 2 2
4 3 1
5 3 2
6 3 3
This is just one of the sample to generate sequence number based on category, it might be other condition as well.
I am trying to generate sequence number for each group of data i get based on id_category field. I tried dense_rank() method but it is not supported for MySQL.
How can i generate sequence number for each group in this way?
DENSE_RANK() OVER (ORDER BY id_category) As seq_no
My query
Product::leftJoin('category','category.id_category','=','product.id_category')
........
->get();
If you don't have huge amounts of data, it's probably easiest to
grab everything
group by category
sort each category by product
loop through each category and set the sequence number based on the current index
While I don't know the exact nature of your tables, it would look something like this, with your query as the start:
Product::leftJoin('category','category.id_category','=','product.id_category')
->get()
->groupBy('category_id')
->each(function ($group) {
$group->sortBy('product_id')
->map(function ($product, $index) {
$product->seq_no = $index + 1;
});
});
Though note that this should be treated as pseudocode and adapted as fits your application best.
I need some help. I need to calculate the sum of numeric field value as per userid and place them into array using MySQL and PHP. I am explaining my table below.
db_like:
id like userid
1 1 10
2 2 11
3 1 10
4 2 11
Here I need to count the sum of like field value as per userid and place the result into array. Please help.
SELECT SUM(`like`) AS `likes` FROM [table] GROUP BY `userid`;
I need to get the top 4 records ordered by a specific column descending. If more than one value is the same then I need to randomise them.
For example:
ID - VALUE
1 - 10
2 - 5
3 - 5
4 - 3
5 - 3
6 - 3
7 - 3
8 - 3
9 - 3
10 - 3
So in this example 10 is the highest so will always be top. 5 is the second highest so it will randomly order both of the 5 values. it will then select a random one with the value of 3.
I hope this is clear.
edit:
I have tried ORDER BY Value DESC and assumed that it would select them randomly but it seems as though there is a predetermined order as the same ones keep displaying.
I have also tried ORDER BY Value DESC, RAND(ID) which does the same as above but with different values.
Use this ORDER clause:
SELECT ... ORDER BY your_column DESC, RAND()
So I have a single table inside which I have a score system for points. It looks something along this line:
Columns:
ID Name Date Points
1 Peter 2014-07-15 5
2 John 2014-07-15 6
3 Bill 2014-07-15 3
and so on...
Everyday, the new results are being put into the table with the total amount of points acumulated, however in order to be able to get historic values, the results are put into new rows. So on the 2014-07-16, the table will look like this:
ID Name Date Points
1 Peter 2014-07-15 5
2 John 2014-07-15 6
3 Bill 2014-07-15 3
4 Peter 2014-07-16 11
5 John 2014-07-16 12
6 Bill 2014-07-16 3
However sometimes when a player doesn't take part for the whole day and doesn't get any points, he will still be added, but the points will remain the same (here this is shown by the case of Bill).
My question is how to count the number of each type of players (active - Peter and John ie when the points value changes from one date to another and inactive - Bill ie when the points value stays the same).
I have managed to get this query to only select players who do have the same value, but it's giving me the list of players rather than the count. Although I could potentialy be wrong with this query:
SELECT Points, name, COUNT(*)
FROM points
WHERE DATE(Date) = '2014-07-15' OR DATE(Date) = '2014-07-16'
GROUP BY Points
HAVING COUNT(*)>1
I'm not sure how to count the number of rows (could do a bypass trick with PHP getting the number of rows, but interested in SQL only) or how to invert it, to get a count of players who have a different score (again, could get total of rows and then subtract the above number, but not interested in that either - I'd prefer the SQL).
Regards and thanks in advance.
You are pretty close.
If you have at most one row per "player" per "date", you could do something like this:
SELECT SUM(IF(c.cnt_distinct_points<2,1,0)) AS cnt_inactive
, SUM(IF(c.cnt_distinct_points>1,1,0)) AS cnt_active
FROM ( SELECT p.name
, COUNT(DISTINCT p.points) AS cnt_distinct_points
FROM points p
WHERE DATE(p.Date) IN ('2014-07-15','2014-07-16')
GROUP BY p.name
) c
The inline view query (aliased as c) gets a count of the distinct number of "points" values for each player. We need to "group by" name, so we can get a distinct list of players, along with an indication whether the points value was different or not. If all of the non-NULL "points" values for a given player are the same, COUNT(DISTINCT ) will return a value of 1. Otherwise, we'll get a value larger than 1.
The outer query processes that list, collapsing all of the rows into a single row. The "trick" is to use expressions in the SELECT list that return 1 or 0, depending on whether the player is "inactive", and perform a SUM aggregate on that. Do the same thing, but a different expression to return a 1 if the player is "active".
If the count of distinct points for a player is 1, we'll essentially be adding 1 to cnt_inactive. Similarly, of the distinct points for a player is greater than 1, we'll be adding 1 to the cnt_active.
If this doesn't make sense, let me know if you have questions.
NOTE: Ideally, we'd avoid using the DATE() function around the p.Date column reference, so we could enable an appropriate index.
If the Date column is defined as (MySQL datatype) DATE, then the DATE() function is unnecessary. If the Date column is defined as (MySQL datatype) DATETIME or TIMESTAMP, we could use an equivalent predicate:
WHERE p.Date >= '2014-07-15' AND p.Date < '2014-07-16' + INTERVAL 1 DAY
That looks more complicated, but a predicate of that form is sargable (i.e. MySQL can use an index range scan to satisfy it, rather than having to look at every row in the table.)
For performance, we'd probably benefit from an index with leading columns of name and date
... ON points (`name`,`date`)
(MySQL may be able to avoid a "Using filesort" operation for the GROUP BY).
I would solve this problem by looking at the previous number of points and then doing a comparison:
select date(date), count(*) as NumActives;
from (select p.*,
(select p2.points
from points p2
where p2.name = p.name and p2.date < p.date
order by p2.date desc
limit 1
) as prev_points
from points p
) p
where prev_points is NULL or prev_points <> points;
Of course, you can add a where clause to get the count for any particular day.
sql column - trans_value contain both positive and negative value amount.
so i'm trying to figure out how do i set a sum of positive value and negative value aside, so that i can calculate the how much sum of positive and how much is sum of negative.
so in the end, i can minus both, positive - negative.
edit,
i forgot to mention before that
there is also column name product id in same table, so
product_id | trans_value
1 200
1 250
1 -150
2 500
2 -300
3 200
3 -150
so i need to get sum of product id 1, display it out, then for 2, 3 and so on.
thanks
If you just want to see the total for each product_id
SELECT product_id, SUM(trans_value)
FROM table
GROUP BY product_id
ORDER BY product_id
If you really need the positive and negative values seperately:
SELECT SUM(IF(trans_value<0;trans_value;0)) neg, SUM(IF(trans_value>0;trans_value;0)) pos
FROM table
Will put the sum of the negative values in neg, the sum of the positive values in pos. pos + neg will be the total sum.
SELECT SUM( trans_value ) AS sum FROM table WHERE trans_value > 0;