Calculations after Summing values in Drupal views with module aggregation plus - php

In Drupal 7, I use the module views aggregation plus.
There are 2 columns (A and B) which I apply a group aggregation of 'Average' and 'Sum' respectively. I want to have a 3rd column (C) which does a math expression (A - B) after the grouping. How can I achieve this? An example below
Before grouping
ID | Column A | Column B | Column C
1 | 5 | 10 | -5
1 | 5 | 10 | -5
2 | 5 | 10 | -5
What I get currently
ID | Column A | Column B | Column C
1 | 5 | 20 | -10
2 | 5 | 10 | -5
What I want to get
ID | Column A | Column B | Column C
1 | 5 | 20 | -15
2 | 5 | 10 | -5
I tried retrieving the values of the summed field using devel module, and while I get this: $...['#views_contextual_links_info']['views_ui']['view']->style_plugin->rendered_fields[2]['expression_1']
I tried outputting that using Views PHP but it doesn't return back the correct value. I believe it is only returning back the value prior to being summed by the views aggregator plus.

You can add the field: Global: Math expression.
It allows you to enter mathematical expressions such as 2 + 2 or sqrt(5).
As it supports Replacement Patterns of the fields you added before, you can easily enter [field_column_A]-[field_column_B]

Related

Make a (composite) primary key for an 'item' table where the incremental 'item_id' resets per 'order_id' foreign key [duplicate]

This question already has answers here:
Custom SERIAL / autoincrement per group of values
(3 answers)
MySQL: Add sequence column based on another field
(3 answers)
MySQL auto-increment based on group
(3 answers)
Closed 4 years ago.
Teacher wants us to discuss how to implement the 'line_item' table of a receipt database for a global business.
He wants us to discuss the primary (composite?) key of such a 'line item' table. If our global business is printing thousands of receipts (with hundreds of items) every minute, how much do we need to consider the possibility of hitting the upper limits of an INT for the line_item_id? Is there a more effective way to handle the line_item id?
"Note: Gaps in numbering (generally caused by deletions) are okay. Also look for possible race conditions."
Consider this: You add 3 receipts with 3 items each. You delete the 2nd item of the 3rd receipt. Then add a new item to the 3rd receipt.
So I'm picturing something like this to start with: (Where receipt #1 and #3 were originally identical before the add/delete exercise. Note the numbering on #3.)
| receipt_id (FK) | line_id (INT) | line_text (TINYTEXT) |
---------------------------------------------------------------------
| 1 | 1 | 'Apple' |
| 1 | 2 | 'Banana' |
| 1 | 3 | 'Coconut' |
---------------------------------------------------------------------
| 2 | 1 | 'Apple' |
| 2 | 2 | 'Apple' |
| 2 | 3 | 'Apple' |
---------------------------------------------------------------------
| 3 | 1 | 'Apple' |
| 3 | 3 | 'Coconut' |
| 3 | 4 | 'Dates' |
---------------------------------------------------------------------
We've been learning SQL and PHP (mySQLi in innoDB if that matters much.)
However I feel this may be accomplished in SQL alone, right?
It appears I should use the MAX() function in the second column to make a COMPOSITE PRIMARY KEY and to avoid worrying about hitting the upper INT threshold.
I'm trying to concoct a MySQL INSERT that would do something dynamic with its numbering of the receipt line, like:
INSERT INTO line_item (3, VALUES MAX(receipt_line)+1, 'Dates')
At the end he has other thoughts like: "What if you now delete and add an item at the end of the second receipt?"
I imagine these are the operations he's looking for:
-- Delete the last line of the second receipt
DELETE FROM line_item WHERE receipt_id=2 AND line_id=MAX(line_id)
-- Add a new line to the second receipt.
INSERT INTO line_item VALUES ( 2, MAX(line_id)+1, 'Watermelon')
And I expect results like:
| receipt_id (FK) | line_id (INT) | line_text (TINYTEXT) |
---------------------------------------------------------------------
| 1 | 1 | 'Apple' |
| 1 | 2 | 'Banana' |
| 1 | 3 | 'Coconut' |
---------------------------------------------------------------------
| 2 | 1 | 'Apple' |
| 2 | 2 | 'Apple' |
| 2 | 3 | 'Watermelon' |
---------------------------------------------------------------------
| 3 | 1 | 'Apple' |
| 3 | 3 | 'Coconut' |
| 3 | 4 | 'Dates' |
---------------------------------------------------------------------
But instead I get a bunch of errors and weird results.
Do I need to use PHP to calculate the line_id instead? What am I missing?
You can't use just MAX(line_id) because that gets the maximum value of line_id across all receipts. What you want is the maximum line_id in one specific receipt. Something like SELECT MAX(line_id) FROM line_item WHERE receipt_id = 3.
You could build that into a single SQL query using a sub select to get the new line_id value. But I think it would be better done in PHP. Determine the new line_id first, then insert your new line item. In two separate queries.
Also think about how your receipt application will delete a line item. If I want to delete the second Apple line item in receipt 2 I would need to know it's line_id. So your application will need to know the line_id of new items it adds.

How to get standard deviation of grouped rows?

I want to calculate the standard deviation between page views on my site. I'd like to do this using pure MySQL - without querying the whole table to the webserver - and return a single number to the PHP code for further use. Each page view is stored as a visitor_id - page_id - visit_count trio as per the following schema:
+============+=========+=============+
| visitor_id | page_id | visit_count |
+============+=========+=============+
| 1 | 2 | 7 |
+------------+---------+-------------+
| 2 | 2 | 4 |
+------------+---------+-------------+
| 1 | 1 | 17 |
+------------+---------+-------------+
| 3 | 2 | 12 |
+------------+---------+-------------+
| 1 | 3 | 639478 |
+------------+---------+-------------+
| 2 | 1 | 6 |
+------------+---------+-------------+
page_id refers to a PRIMARY_KEY in the pages table, visitor_id refers to a PRIMARY_KEY in the visitors table. The above table's primary key is the visitor_id - page_id pair, since the same page seen by the same visitor is recorded by increasing the visit_count of the corresponding row, instead of creating a new one.
Before calculating standard deviation, the entries should be grouped together by page_id, their visit_count summed (visitor_id can be ignored here), so, effectively, I want to calculate the deviation of the following:
+=========+=============+
| page_id | visit_count |
+=========+=============+
| 2 | 23 |
+---------+-------------+
| 1 | 23 |
+---------+-------------+
| 3 | 639478 |
+---------+-------------+
I'm aware of the possible PHP solutions, but I'm interested in a MySQL one.
If you want the standard deviation for each page (i.e., the visitors are the population):
select page_id, sum(visit_count) as visit_count, std(visit_count) as visit_std
from table1
group by page_id;
If you want the standard deviation over the pages:
select std(visit_count) as page_std
from (select page_id, sum(visit_count) as visit_count
from table1
group by page_id
) t;
You could create a new table that stores timestamp + current views so you can view a history of changes in views. You'd be able to check the last two timestamped entries and how much the difference is between the two as well as a whole bunch of other stuff you haven't even thought of yet. Like graphs. Or pie charts showing activity increases per week day. Mmmm pie.

MySQL mylty sorting a table

I have a MySQL table users:
# | name | parent|
________________________
1 | USER 1 |
2 | USER 2 |
3 | user 12 | 1
4 | user 22 | 2
5 | user 11 | 1
6 | USER 3 |
7 | user 21 | 2
8 | user 31 | 6
Here the parent record is the primary key of the same table. What i need is to sort the table both parent-wise and name-wise.
This is the result that I need to get:
# | name | parent|
________________________
1 | USER 1 |
5 | user 11 | 1
3 | user 12 | 1
2 | USER 2 |
7 | user 21 | 2
4 | user 22 | 2
6 | USER 3 |
8 | user 31 | 6
If you only have one level of parents you can do:
select u.*
from users u
order by coalesce(parent, #), #;
(This assumes that the id of the parent is smaller than the id of the children, as is the case with the sample data in the question.)
If you have multiple levels of parents (grandparents and so on), then a single MySQL query is problematic. MySQL doesn't directly support hierarchical or recursive queries.
Although I do not know your use case, I think what you are doing is a symptom of poor design.
If possible, a rethink might be in order.
Nevertheless, I think this works
SELECT * FROM users
ORDER BY
CASE `parent`
WHEN NOT NULL THEN `parent`
ELSE SUBSTRING_INDEX(`users`.`name`, ' ', -1) END
ASC
Simple explanation:
Sorts by parent field if not null.
Otherwise use the number found in the name field (extracted by separating by the space).
Assumes number will always be separated by a space, and as with Gordon's answer, only works with a single parent.

Fixture generator in PHP or MySQL

I am trying to generate fixtures for a sports website. I have a table called Members, with relevant columns being member_id and league_id. The league_id will be passed from a form on the previous page as the variable $leagueid.
I'm pulling out all the member ID's relating to that league ID using...
$result = mysql_query("SELECT member_id FROM Members WHERE league_id = '$leagueid'")
I now need to generate fixtures for all these member ID's and then insert that data into the MySQL table 'Fixtures'. Each row of data in that table needs to include:-
player1 - member_id of the first player
player2 - member_id of the second player
week - integer showing which week the match will be played
league_id
However, there are some special conditions that also need to be applied.
Every 3rd week needs to remain free (i.e. weeks 3,6,9,12 etc). No matches can be scheduled on these weeks
There needs to be an option (which will be selected and passed from a form on the previous page as a checkbox variable called $double) which will double up the matches. This means that after generating one complete round of fixtures, you need to take the generated list, swap ID's for players 1 and 2, and duplicate them all. So 1 round of fixtures could look like this....
Week 1
1 vs 2
3 vs 4
Week 2
1 vs 3
2 vs 4
Week 3
1 vs 4
2 vs 3
Then you would swap the ID's and add on another set...
Week 4
2 vs 1
4 vs 3
Week 5
3 vs 1
4 vs 2
Week 6
4 vs 1
3 vs 2
What I'm looking for is some code that will generate all these fixtures while keeping in mind all the special conditions that I've listed.
I know this is all possible in PHP but I also think I can do it using one SQL query instead, which might be a lot cleaner. Can anyone help me out?? Thanks!!
P.S. I know I'm using mysql and not mysqli. I am currently trying to transfer over to mysqli but I'm having some problems which I have posted on a separate question that I have yet to get a correct answer to.
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
SELECT * FROM ints WHERE MOD(i,3) > 0;
+---+
| i |
+---+
| 1 |
| 2 |
| 4 |
| 5 |
| 7 |
| 8 |
+---+
The second part is simply
INSERT INTO my_table SELECT week_id+3, column_2, column_1 FROM my_table;

mysql select data when one field may or may not contain values

Have a MYSQL look up table that returns the points received for a certain place(P) among a number of finishers(N), with a variety of formats(points_id). Different point structures are used for different events. Some times the points awarded depend on the number of finishers(N) Sometimes they don't.
Here is a short version of the table, with two sample structures.
points_id -1 the points depends on N Point_id -2 the points don't.
points
points_id | P | N | points |
1 | 1 | 3 | 90 |
1 | 1 | 2 | 85 |
1 | 1 | 1 | 80 |
1 | 2 | 3 | 60 |
1 | 2 | 2 | 50 |
1 | 3 | 3 | 30 |
3 | 1 | | 100 |
3 | 2 | | 90 |
3 | 3 | | 80 |
3 | 3 | | 70 |
So my question:
1) is there a way to put the wildcard in the table data.
eg if the N column that shows blank had a % in it
and I did this query.
SELECT points from t1 WHERE points_id=3 and P=3 and N=2
It would return 96??
PS I know this doesn't work but is shows my idea.
2) I want it to be fast, may put it in a procedure to use in larger queries. I am guessing unless there is a very simple way to do what I show above. the fastest method will be to have rows for all of the different N's in the points_id =3 case. Is that true?
You might consider UNION ALL:
SELECT points from t1 WHERE points_id=3 AND P=3
UNION ALL
SELECT points from t1 WHERE points_id=3 AND N=2
This will get the results regardless if P=3 or N=2. I copied your database schema and tried this, and it produced:
points
------
80
70
If you do want this to be fast with a large amount of data--you'll really want to have an index and/or primary key.
Try this :
SELECT points from t1 WHERE points_id=3 and P=3 and (N=2 OR (IFNULL(N,'')=''))
// dataType of N varchar
SELECT points from t1 WHERE points_id=3 and P=3 and (N=2 OR (IFNULL(N,0)=0))
// dataType of N numeric type
Let me know if there is any change or am getting you wrong

Categories