PHP / SQL - Get sum of another column - php

I have two tables in my MySQL database. One is called players and the other table is called worlds. Each player has a "level" and a "world" column. What I want to achieve is to fill up the columns in the table world based on the column values from table players. I want to first of all get the sum of players on that world and also an average of their levels.
My tables look like this:
Table: Players
+-------+-------+--------+----------+-------+--------------+---------+--------+
| id | name | sex | vocation | level | achievements | world | online |
+-------+-------+--------+----------+-------+--------------+---------+--------+
| 24471 | John | Male | None | 92 | 3 | Antica | 1 |
| 24493 | Bob | Male | None | 76 | 19 | Amera | 0 |
| 24535 | Sam | Male | None | 75 | 0 | Antica | 0 |
| 24574 | Sarah | Female | None | 78 | 23 | Beneva | 1 |
| 24673 | Carl | Male | None | 75 | 10 | Belobra | 1 |
+-------+-------+--------+----------+-------+--------------+---------+--------+
Table: Worlds
+----+---------+---------+--------+--------+----------+---------------+--------------+
| id | name | players | online | avglvl | totalexp | location | pvp |
+----+---------+---------+--------+--------+----------+---------------+--------------+
| 1 | Amera | 0 | 0 | 0 | 0 | North America | Open PvP |
| 2 | Antica | 0 | 0 | 0 | 0 | Europe | Open PvP |
| 3 | Astera | 0 | 0 | 0 | 0 | North America | Optional PvP |
| 4 | Belobra | 0 | 0 | 0 | 0 | South America | Optional PvP |
| 5 | Beneva | 0 | 0 | 0 | 0 | Europe | Optional PvP |
+----+---------+---------+--------+--------+----------+---------------+--------------+
So for example, we can see that the players John and Sam have the world Antica. Therefore, Antica should have the value "2" under the player column in the table world. But only John is online on Antica. So the world Antica should have the value "1" under the column "online" in the table "world". And so on. I also want their average level on that world.
How can I achieve this with PHP by making an SQL query?
First I need to get all the world names (I think?) and loop through them. And then get the following details for each world:
Player amount
Online amount
Average level amount
And then make an update in to worlds table with those values..

You can summarize the data as:
select world, count(*) as players, sum(online) as online, avg(level) as avglevel
from players
group by world;
You can incorporate this into an update:
update worlds w join
(select world, count(*) as players, sum(online) as online, avg(level) as avglevel
from players
group by world
) p
on w.world = p.world
set w.players = p.player,
w.online = p.online,
w.avglevel = p.avglevel;
I don't think maintaining a separate table like this is a good idea. After all, you can always just query players to get this information. Also the two systems can quickly get out-of-date, so the data is inconsistent. You would fix that by using triggers, but that adds complexity to the system. In general, a simple query is quite sufficient.

Related

Mysql query: Find least used words

I have a table of words used in the title of articles. I want to find which words which are used the least in the set or article titles.
Example:
Titles:
"Congressman Joey of Texas does not sign bill C1234."
"The pretty blue bird flies at night in Texas."
"Congressman Bob of Arizona is the signs bill C1234."
The table would contain the following.
Table WORDS_LIST
----------------------------------------------------
| INDEX ID | WORD | ARTICLE ID |
----------------------------------------------------
| 1 | CONGRESSMAN | 1234 |
| 2 | JOEY | 1234 |
| 3 | SIGN | 1234 |
| 4 | BILL | 1234 |
| 5 | C1234 | 1234 |
| 6 | TEXAS | 1234 |
| 7 | PRETTY | 1235 |
| 8 | BLUE | 1245 |
| 9 | BIRD | 1245 |
| 10 | FLIES | 1245 |
| 11 | NIGHT | 1245 |
| 12 | TEXAS | 1245 |
| 13 | CONGRESSMAN | 1246 |
| 14 | BOB | 1246 |
| 15 | ARIZONA | 1246 |
| 16 | SIGNS | 1246 |
| 17 | BILL | 1246 |
| 18 | C1234 | 1246 |
----------------------------------------------------
In this case, the words "pretty,blue, flies, night" would be the used in the least number of articles.
I would appreciate any ideas on how to best create this query. So far below is what I started with. I can also write something in PHP but figured a query would be faster.
SELECT distinct a1.`word`, count(a1.`word`)
FROM mmdb.words_list a1
JOIN mmdb.words_list b1
ON a1.id = b1.id AND
upper(a1.word) = upper(b1.word)
where date(a1.`publish_date`) = '2017-06-09'
group by `word`
order by count(a1.`word`);
I don't see why a self-join is necessary. Just do something like this:
select wl.word, count(*)
from mmdb.words_list wl
where date(wl.`publish_date`) = '2017-06-09'
group by wl.word
order by count(*);
You can add a limit to get a fixed number of words. If publish_date is already a date, you should do the comparison as:
where publish_date = '2017-06-09'
If it has a time component:
where publish_date >= '2017-06-09' and publish_date < '2017-06-10'
This expression allows MySQL to use an index.
Try this. It's a bit more simple and should return the correct results:
SELECT `WORD`,
COUNT(*) as `num_articles`
FROM `WORDS_LIST`
WHERE date(`publish_date`) = '2017-06-09'
GROUP BY `WORD`
ORDER BY COUNT(*) ASC;

Find the ranking for Concatenated rows in mysql

I have a table with concatenated values within both rows, I am therefore uniquely retrieve ranking for each row in the tables.
UPDATE
The other tables has been added to question
NamesTable
NID | Name |
1 | Mu |
2 | Ni |
3 | ices |
GroupTable
GID | GName |
1 | GroupA |
2 | GroupB |
3 | GroupC |
MainTable
| NID | Ages | Group |
| 1 | 84 | 1 |
| 2 | 64 | 1 |
| 3 | 78 | 1 |
| 1 | 63 | 2 |
| 2 | 25 | 2 |
| 3 | 87 | 2 |
| 1 | 43 | 3 |
| 2 | 62 | 3 |
| 3 | 37 | 3 |
Now the first Name is equated to the first age in the table, I am able to equate them using php and foreach statements, Now the problem is with the ranking of the ages per each group. I am ranking the names uniquely on each row or group.
Results which is expected
| Names | Ages | Group | Ranking |
| Mu,Ni,ices | 84,64,78 | 1 | 1,3,2 |
| Mu,Ni,ices | 63,25,87 | 2 | 2,3,1 |
| Mu,Ni,ices | 43,62,37 | 3 | 2,1,3 |
In my quest to solving this, I am using GROUP_CONCAT, and I have been able to come to this level in the below query
SELECT
GROUP_CONCAT(Names) NAMES,
GROUP_CONCAT(Ages) AGES,
GROUP_CONCAT(Group) GROUPS,
GROUP_CONCAT( FIND_IN_SET(Ages, (
SELECT
GROUP_CONCAT( Age ORDER BY Age DESC)
FROM (
SELECT
GROUP_CONCAT(Ages ORDER BY Ages DESC ) Age
FROM
`MainTable` s
GROUP by `Group`
) s
)
)) rank
FROM
`MainTable` c
GROUP by `Group`
This actually gives me the below results.
| Names | Ages | Group | Ranking |
| 1,2,3 | 84,64,78 | 1 | 7,9,8 |
| 1,2,3 | 63,25,87 | 2 | 5,6,4 |
| 1,2,3 | 43,62,37 | 3 | 2,1,3 |
The only problem is that the ranking Values increase from 1 to 9 instead of ranking each row uniquely. Its there any idea that can help me cross over and fix this? I would be grateful for your help. Thanks

MySQL - PHP unique values from rows

I have this table:
table 1
+----+-----------------------+----------+------+-------+
| ID | COUNTRY | QUANTITY | EACH | PRICE |
+----+-----------------------+----------+------+-------+
| 1 | U.S.A | 1 | 12 | 1*12 |
| 2 | U.K. | 2 | 3 | 2* 3 |
| 3 | GERMANY | NULL | 3 | |
| 4 | FRANCE;GERMANY; U.S.A | 0 | 7 | |
| 5 | U.S.A;GERMANY | 3 | 8 | 3*8 |
| 6 | FRANCE;U.K. | 1 | 10 | 1*10 |
| 7 | U.S.A;FRANCE | 2 | 6 | 2*6 |
| 8 | FRANCE;FRANCE | 9 | 3 | 9*3 |
+----+-----------------------+----------+------+-------+
and this code sql:
SELECT
COUNTRY,
SUM(COALESCE(IF(QUANTITY = NULL OR QUANTITY = 0,1,QUANTITY), 1) * EACH) AS PRICE
FROM table1
GROUP BY COUNTRY
How could I make unique values for the country column and return: USA = 48 (ID: 1+5+7); UK= 6; GERMANY=3; FRANCE = 44 (ID: 4+6+8). I want that the rows, those contain two, three, four countries to be eliminated and to remain only the first country from row.
Thank you!
Use substring_index to get the first country in the ;-separated list.
SELECT
SUBSTRING_INDEX(COUNTRY, ';', 1) AS COUNTRY
SUM(IF(QUANTITY IS NULL OR QUANTITY = 0,1,QUANTITY) * EACH) AS PRICE
FROM table1
GROUP BY COUNTRY
It would be much more complicated if you wanted to keep all the rows where each country appears (in that case I would recommend doing it in PHP, not MySQL, since MySQL doesn't have a builtin way to do explode()).

mysql match value, find similar and sort, then order the sorted groups by orginal match value

Can't seem to get this query right. Here's what I need to do.
Get by Age under 40, example return...
| NAME |--| AGE |
|------|--|-----|
| Amy | | 26 |
| John | | 22 |
| Dan | | 30 |
Find Names that are like the names returned from above and sort alphabetically...
| NAME |--| AGE |
|------|--|-----|
| Aaron| | 33 |
| Amy | | 26 |
| Jacob| | 25 |
| John | | 22 |
| Dan | | 30 |
Sort the alphabetical groups by original returned age values values...
| NAME |--| AGE |
|------|--|-----|
| Jacob| | 25 |
| John | | 22 |-->was youngest from first query so his group goes first
| Aaron| | 33 |
| Amy | | 26 |
| Dan | | 30 |
This should allow you to order the results by age then names that match the first letter of the person of that person. The OTHER p1 CRITERIA should be replaced with whatever other criteria you are using to determine the first group:
SELECT p2.NAME, p2.AGE
FROM PEOPLE p1
JOIN PEOPLE p2
ON substring(p1.NAME,1,1) = substring(p2.NAME,1,1)
WHERE p1.AGE < 40
AND OTHER p1 CRITERIA
ORDER BY p1.AGE, p2.NAME

MYSQL: Search for User ID in one table to search for data in 2 other tables, then show data from all 3 tables

I have a database with entries similar to the following...
users:
+-----+------+----------+---------+-------+
| UID | Name | Addr | City | State |
+-----+------+----------+---------+-------+
| 1 | John | 101 Main | Austin | TX |
| 2 | John | 101 Main | Houston | TX |
| 3 | John | 101 Main | Del Rio | TX |
| 4 | John | 101 Main | Houston | TX |
+-----+------+----------+---------+-------+
verification:
+-----+---------------+--------------+
| UID | LicenseFirst3 | LicenseLast3 |
+-----+---------------+--------------+
| 1 | 554 | 122 |
| 2 | 556 | 345 |
| 3 | 555 | 382 |
| 4 | 555 | 108 |
+-----+---------------+--------------+
section_user_map:
+-----+-----------+---------------------+
| UID | SectionID | CompleteDate |
+-----+-----------+---------------------+
| 1 | 65 | 2012-05-12 05:05:15 |
| 2 | 72 | 2012-05-06 14:03:15 |
| 3 | 65 | 2012-05-09 16:13:15 |
| 4 | 72 | 2012-05-06 18:14:15 |
+-----+-----------+---------------------+
I need to be able to search for students who completed section 65 between noon on day X and noon on day Y. I also need to show the student's name, address, city, state and first and last three digits of their license number. I believe this will require both a left join and union command but it's getting a bit too complicated to formulate.
SELECT *
FROM section_user_map
JOIN users USING (UID)
JOIN verification USING (UID)
WHERE SectionID = 65
AND CompleteDate BETWEEN '2012-05-09 12:00:00'
AND '2012-05-11 12:00:00'
See it on sqlfiddle.
No UNION required. Outer join would only be required if you still want to return results for users who do not exist in one (or both) of the users or verification tables.

Categories