How to replace Over clause in sql version 4.9.5 - php

I am trying to run a query to find the count and percentage of artisan based on gender. The query is running absolutely fine on the SQL server 8. But not on my live server which is 4.9.5.
The below is my query.
SELECT industry
, count(*) as cnt
, (count(*)*100.0/sum(count(*))over()) as perc
FROM `artisan_work`
GROUP BY industry
ORDER BY cnt DESC

In any database, you should be able to use:
SELECT aw.industry, count(*) as cnt,
count(*) * 100.0 / tot.cnt as perc
FROM artisan_work aw cross join
(SELECT COUNT(*) as cnt FROM artisan_work) tot
GROUP BY aw.industry
ORDER BY cnt DESC

SELECT industry
, count(*) as cnt
, (count(*)*100.0/(select count(*) from artisan_work )) as perc
FROM artisan_work a
GROUP BY industry
ORDER BY cnt DESC

Related

Multiple Counts in MYSQL PHP Query

I'm trying to create a leaderboard but i'm not sure how to do the mysql query.
I would like to count all the levels from a player in the skills table and get the total Level and count all the experience from a player in the experience table and get the Total Exp along with displaying the persons name from the users column.
There is 3 tables factions_mcmmo_users, factions_mcmmo_experience, factions_mcmmo_skills.
This is what i have so far but it doesn't work:
$sql = ("SELECT a.id,
(SELECT COUNT(*) FROM factions_mcmmo_experience WHERE user_id = a.id) as TotalXP,
(SELECT COUNT(*) FROM factions_mcmmo_skills WHERE user_id = a.id) as TotalLevel
FROM (SELECT DISTINCT id FROM factions_mcmmo_users) a LIMIT 10;");
Any help would be very appreciated
EDIT: I have it working now but i'm unsure if its the most efficient way to do things so if anyone could help me out if theres a better way, it would mean a lot.
I would also like to know if it's possible to display the total exp and level with commas if the number is in the thousands for example: total level 5,882 and total xp 582,882
EDIT 2:
I have figured out how to format the numbers but still don't know if my code is efficient
$sql = ("SELECT id, user,
(SELECT FORMAT(Sum(taming)+Sum(mining)+Sum(woodcutting)+Sum(repair)+Sum(unarmed)+Sum(herbalism)+Sum(excavation)+Sum(archery)+Sum(swords)+Sum(axes)+Sum(acrobatics)+Sum(fishing)+Sum(alchemy),0) FROM factions_mcmmo_skills b WHERE b.user_id = a.id) as TotalLevel,
(SELECT FORMAT(Sum(taming)+Sum(mining)+Sum(woodcutting)+Sum(repair)+Sum(unarmed)+Sum(herbalism)+Sum(excavation)+Sum(archery)+Sum(swords)+Sum(axes)+Sum(acrobatics)+Sum(fishing)+Sum(alchemy),0) FROM factions_mcmmo_experience c WHERE c.user_id = a.id) as TotalXP
FROM (SELECT id, user FROM factions_mcmmo_users) a group by id ORDER BY TotalLevel DESC, TotalXP DESC LIMIT 10;");
EDIT 3
Updated code from scaisEdge but was displaying everyones level as 1 and XP as 1, so i changed count(*) changed to sum, added an order By TotalLevel in Descending order and that seems to have worked but i can't get it to display the persons name (user column) in the user table? not sure if i was supposed to change to sum because it didn't work the other way.
$sql = ("SELECT a.id, b.TotalXP, c.TotalLevel
FROM (SELECT DISTINCT id FROM factions_mcmmo_users) a
INNER JOIN (
SELECT user_id, Sum(taming)+Sum(mining)+Sum(woodcutting)+Sum(repair)+Sum(unarmed)+Sum(herbalism)+Sum(excavation)+Sum(archery)+Sum(swords)+Sum(axes)+Sum(acrobatics)+Sum(fishing)+Sum(alchemy) as TotalXP
FROM factions_mcmmo_experience
GROUP By user_id
) b on b.user_id = a.id
INNER JOIN (
SELECT user_id, Sum(taming)+Sum(mining)+Sum(woodcutting)+Sum(repair)+Sum(unarmed)+Sum(herbalism)+Sum(excavation)+Sum(archery)+Sum(swords)+Sum(axes)+Sum(acrobatics)+Sum(fishing)+Sum(alchemy) as TotalLevel
FROM factions_mcmmo_skills
GROUP by user_id
) c on c.user_id = a.id
ORDER BY TotalLevel DESC
LIMIT 10;");
EDIT 4
Everything working but when i try to format the totals using "FORMAT(Sum(Columns), 0) on the inner joins, the EXP Total appears to work but the main Total Level is not displaying results that are over 1,000 and it breaks the leaderboard positioning, it should be sorting them on total level but it appears to be random, when u remove the format,0 it goes back to working
I would like it to display commas if the number number is the thousands for example: Total Level: 5,532 and Total EXP 5882,882
See live demo: http://mcbuffalo.com/playground/leaderboards/server/factions-mcmmo.php
Updated Code trying to use Format:
$sql = ("SELECT a.id, a.user, b.TotalXP, c.TotalLevel
FROM (SELECT id, user FROM factions_mcmmo_users) a
INNER JOIN (
SELECT user_id, FORMAT(Sum(taming)+Sum(mining)+Sum(woodcutting)+Sum(repair)+Sum(unarmed)+Sum(herbalism)+Sum(excavation)+Sum(archery)+Sum(swords)+Sum(axes)+Sum(acrobatics)+Sum(fishing)+Sum(alchemy), 0) as TotalXP
FROM factions_mcmmo_experience
GROUP By user_id
) b on b.user_id = a.id
INNER JOIN (
SELECT user_id, FORMAT(Sum(taming)+Sum(mining)+Sum(woodcutting)+Sum(repair)+Sum(unarmed)+Sum(herbalism)+Sum(excavation)+Sum(archery)+Sum(swords)+Sum(axes)+Sum(acrobatics)+Sum(fishing)+Sum(alchemy), 0) as TotalLevel
FROM factions_mcmmo_skills
GROUP by user_id
) c on c.user_id = a.id
ORDER BY TotalLevel DESC;");
EDIT 5
Changed number with PHP, everything works
Original Images
you could use an couple of inner join
$sql = ("SELECT a.id, a.name, b.TotalXP, c.TotalLevel
FROM (SELECT DISTINCT id, name FROM factions_mcmmo_users) a
INNER JOIN (
SELECT user_id, COUNT(*) as TotalXP
FROM factions_mcmmo_experience
GROUP By user_id
) b on b.user_id = a.id
INNER JOIN (
SELECT user_id, COUNT(*) as TotalLevel
FROM factions_mcmmo_skills
GROUP by user_id
) c on c.user_id = a.id
LIMIT 10

UNION ALL - return from which table the result is

I have this code running (Thanks to #Gordon Linoff).
SELECT alid, max(ts) as ts
FROM ((SELECT AL.alID, AL.al_date AS ts FROM AL)
UNION ALL
(SELECT MRA.mraNR, MRA.add_date FROM MRA)
UNION ALL
(SELECT AMG.mraNR, AMG.lastupd FROM AMG)
) t
GROUP BY alID
ORDER BY ts DESC
LIMIT 20;
Now we need to have a third value, knowing from which table the result comes (AL, MRA or AMG).
Already tried options like this, but nothing seems to work.
SELECT alid, TABLEVALUEWENEED as RES, max(ts) as ts
FROM ((SELECT AL.alID, TABLEVALUEWENEED AS RES1, AL.al_date AS ts FROM AL)
UNION ALL
(SELECT MRA.mraNR, TABLEVALUEWENEED AS RES2, MRA.add_date FROM MRA)
UNION ALL
(SELECT AMG.mraNR, TABLEVALUEWENEED AS RES3, AMG.lastupd FROM AMG)
) t
GROUP BY alID
ORDER BY ts DESC
LIMIT 20;
And, to get those tables values as php output like:
$RES1=$rows["RES1"];
Any help is appreciated!
Just put the string with the table name instead of TABLEVALUEWENEED:
SELECT alid, RES1, max(ts) as ts
FROM ((SELECT AL.alID, 'AL' AS RES1, AL.al_date AS ts FROM AL)
UNION ALL
(SELECT MRA.mraNR, 'MRA' AS RES1, MRA.add_date FROM MRA)
UNION ALL
(SELECT AMG.mraNR, 'AMG' AS RES1, AMG.lastupd FROM AMG)
) t
GROUP BY alID
ORDER BY ts DESC
LIMIT 20;
I also assume you wanted the alias to always be 'RES1' not 'RES1', 'RES2', 'RES3', because the name of the column will be the alias from the first SELECT of the UNION anyway.

Order by rand() on a large mysql database

My site is very slow with because of this mysql query.
SELECT content.*,
(SELECT content_views.views FROM content_views WHERE content_views.content = content.record_num) as views ,
(SELECT images.filename FROM images WHERE images.record_num = content.thumbnail) AS thumbfile
FROM content WHERE enabled = 1 $filterAnd
ORDER BY RAND()
LIMIT $from,$max_results
I know the best way is to use it like this:
SELECT name
FROM random AS r1 JOIN
(SELECT CEIL(RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
But i am using multiple mysql tables i have no idea how i can use my query like this someone that can help me ?
Thank you
edit:
I have tried:
SELECT content.*,
(SELECT content_views.views FROM content_views WHERE content_views.content = content.record_num) as views ,
(SELECT images.filename FROM images WHERE images.record_num = content.thumbnail) AS thumbfile
FROM content AS r1 JOIN
(SELECT (RAND() * (SELECT MAX(record_num) FROM content)) AS id) AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
but now i get the error: Unknown table 'content'
This code selects one random row from content table.
(SELECT
*
FROM
content AS r1
JOIN
(SELECT
CEIL(RAND() * (SELECT
MAX(id)
FROM
content WHERE enabled = 1 $filterAnd)) AS id
) AS r2
WHERE
r1.id >= r2.id AND r1.enabled=1 AND $filterAnd
ORDER BY r1.id ASC
LIMIT 1) randomTable
Now you need to think about this query as an table with name randomTable fields as in content table. Now you can SELECT from it, JOIN it, to do all what you need. Pay attention to $filterAnd - I used it twice. This will work only if $filterAnd contain conditions related to content table.
You have given the table content an alias called r1. You then need to use that alias for references to that particular table:
SELECT r1.*,
(SELECT cv.views
FROM content_views cv
WHERE cv.content = r1.record_num
) as views,
(SELECT i.filename
FROM images i
WHERE i.record_num = r1.thumbnail
) AS thumbfile
FROM content r1 JOIN
(SELECT RAND() * (SELECT MAX(record_num) FROM content) AS id
) r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
This version has table aliases for many of the tables.
Most of the suggestions so far assume an AUTO_INCREMENT id with no holes. If that does not apply, see my blog for that solution, plus 7 more.

How break ties after getting rank

I have a query that gets me a users rank in a table of scores.
SELECT
*
FROM
(SELECT
*, #rank:=#rank + 1 rank
FROM
(SELECT
user_id, SUM(round_total) TotalPoints
FROM
sx14sp_mem_picks
GROUP BY user_id) s, (SELECT #rank:=0) init
ORDER BY TotalPoints DESC) r
WHERE
user_id = 22234
There is a problem with ties. I have a table field "pick_date" that i would like to use to break ties with. The user who made his picks first beats the tie.
Any ideas?
If sx14sp_mem_picks.pickdate is the field to break ties then in the order by sx14sp_mem_picks subquery, add
min( pickdate) asc
This will put the earliest pickdate first - you have to use MIN() bc you need to use an aggregate function given the use of "group by".
You need to order by the pick date in addition to the total points. However, you are talking about multiple rows per user. So, let's take the last pick date:
SELECT *
FROM (SELECT *, (#rank:=#rank + 1) as rank
FROM (SELECT user_id, SUM(round_total) as TotalPoints, max(pick_date) as max_pick_date
FROM sx14sp_mem_picks
GROUP BY user_id
) s CROSS JOIN
(SELECT #rank := 0) init
ORDER BY TotalPoints DESC, max_pick_date asc
) r
WHERE user_id = 22234;

mySQL - Using two JOINs in one query?

I am trying to use two JOIN statements in one query,
$sqlsorgu = mysql_query("SELECT *, COUNT(*), AVG(clicks), AVG(scrolls), AVG(spent)
FROM track where referid='".$memberr."' GROUP BY referer ORDER BY id desc limit 15
JOIN
(
select id, country, num, num*100/total pct
from (SELECT id,country, count(*) as num
FROM track GROUP BY country
ORDER BY num desc limit 5) x
join (select count(*) total from track) y
) tc on t.id = tc.id") or die(mysql_error());
but I am getting this error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'JOIN ( select id, country, num, num*100/total pct from (SELECT id,country' at line 1
What is the correct way to use it ?
GROUP BY/ WHERE/ Order by come after join statements. Try reording like:
"SELECT *, COUNT(*), AVG(clicks), AVG(scrolls), AVG(spent)
FROM track t
JOIN
(
select id, country, num, num*100/total pct
from (SELECT id,country, count(*) as num
FROM track GROUP BY country
ORDER BY num desc limit 5) x
join (select count(*) total from track) y
) tc on t.id = tc.id
where referid='".$memberr."'
GROUP BY referer
ORDER BY tc.id desc limit 15

Categories