How to count users in table with php - php

in wordpress custom php this code works:
$result = count_users();
echo 'There are ', $result['total_users'], ' total users';
foreach($result['avail_roles'] as $role => $count) {
echo $count, ' are ', $role, 's', ', ' . "<br />";
}
echo '.' . "<br />";
Here is an example of output by that:
There are 14 total users
1 are administrators,
3 are s2member_level1s,
13 are access_s2member_ccap_video,
13 are access_s2member_ccap_saas,
1 are access_s2member_ccap_optins,
10 are subscribers,
So, is there a way to count all users with a role, like say: s2member_level1s, or access_s2member_ccap_saas with just one call, or do I have to do it like that, then count the foreach results, every time?
I am hoping there is a way to just count them with one pull, so it does not take a lot of resources and time for the page to load, everytime we load the page.
Thanks,
-Rich

Since you're looping through the results and print the key of each one, you should be able to access directly the result using the key:
$result = count_users();
echo $result['avail_roles']['s2member_level1s'];
Here's more information on arrays: http://php.net/manual/en/language.types.array.php

You can do this by simply executing mysql query, without running a php loop . You just need to use group by with your column name that defines roles(e.g. roletype).
SELECT count(*), roletype FROM `user` group by roletype

you can change the query this way to get results instantly from database single query
select user_id,
count(*) totalusers,
sum(case when avail_roles = 'administrators' then 1 else 0 end) administratorsCount,
sum(case when avail_roles = 's2member_level1s' then 1 else 0 end) s2member_level1sCount,
............
from userstable
group by user_id
So administratorsCount gives number of administrators etc..

Related

Ratio of sum of one column by count of another column

I'm trying to count the number of passed quizzes, as per the following results table:
So, we have 3 quizzes, and if the proportion of correct answers is >= 0.5, then it is passed. If the answer is correct, the result column shows 1, otherwise it shows 0.
For example, quiz 1 has 5 questions, of which 3 are correct. Quiz 2 has 3 questions, of which 1 is correct. Quiz 3 has 2 questions, both are correct.
So, this user has passed 2 quizzes out of 3.
My expected result is: "2 quizzes out of 3 are passed." using MYSQL with PHP with something like:
$number_of_quizzes = 'SELECT COUNT(DISTINCT quiz_id) FROM TABLE'
But, I'm struggling with the query to count the number of rows in the 'result' column and the sum of its values - per quiz.
Is this possible to do with MYSQL alone, or should the logic be transferred to PHP? How?
Can anyone help?
Try this :
$quiz_list = 'SELECT DISTINCT quiz_id FROM TABLE'
$count = 0
$number_of_quizzes = 'SELECT COUNT(DISTINCT quiz_id) FROM TABLE'
foreach ($quiz as &$quiz_list) {
$nb_quiz = 'SELECT COUNT(*) FROM TABLE WHERE quiz_id = ' . $quiz . '';
$nb_correct = 'SELECT COUNT(*) FROM TABLE WHERE quiz_id = ' . $quiz . ' AND result = 1';
$count += ($nb_correct / $nb_quiz > 0.5 ? 1 : 0);
}
$expected_result = $count . " quizzes out of " . $number_of_quizzes . " are passed.";
Of corse you have to change my SQL queries in string to real queries.

Determine the next number in database query with while loop in php

I have a Part Management system I've created in PHP with MySQL. What I'm trying to create is something that will generate the next Part Number for me. All part numbers start with a 3 letter prefix (which is determined by the product family/category) followed by their number.
For example 'ABC001'
What I have below is something that I'd like to use to determine what the next number is having already 'ABC001', 'ABC002' & 'ABC003' so I would like it to recognize what the next number is by querying until the query comes back false because that product number doesn't exist yet.
$abc_query = "SELECT * FROM products WHERE id LIKE 'ABC%'";
$abc_result = $mysqli2->query($abc_query);
while($row = $abc_result->fetch_assoc()) {
$rowid = $row["id"];
$pnumber = substr($rowid, 3, 3);
echo $pnumber. '<br/>';
$int = (int)$pnumber;
$abc_query2 = "SELECT * FROM products WHERE id 'ABC" . sprintf('%03s', $int);
for ($abc_query2 = true; $abc_query2 = false; $int++){
echo $int;
}$abc_nextnumber = $int +1;
}
$abc_newnumber = 'ABC' . sprintf('%03s', $abc_nextnumber);
echo $abc_newnumber;
The result I get is
001
002
003
005
ABC006
However the result should be..
001
002
003
ABC004
code update I've updated the code but it doesn't seem to stop at ABC004 if I have an 005. It will go to 006.
You should have the db do this instead of your app:
select t.id_prfx, max(t.id_num) as latest_num from
(select substring(id, 1, 3) as id_prfx,
cast(substring(id,4) as integer) as id_num) t
group by id_prfx
This will give you a result table where you get the highest part number for each prefix.
If you really really only want prefixes of 'ABC' then:
select max(cast(substring(id,4) as integer)) as max_num from table
where id LIKE 'ABC%'
Could you try this query?
SELECT MAX(SUBSTR(id, 4)) as last_id FROM products WHERE SUBSTR(id, 1, 3)='ABC'
EDİT:
products TABLE
==============
ABC001
ABC002
ABC003
ABC005
==============
We want to find 4 in products table.
SELECT SUBSTR(t1.id, 4) + 1 as POSSIBLE_MIN_ID
FROM products t1
WHERE NOT EXISTS (
SELECT *
FROM products t2
WHERE SUBSTR(id, 1, 3)='ABC' AND SUBSTR(t2.id, 4) = SUBSTR(t1.id, 4) + 1
) LIMIT 1
RESULT:
POSSIBLE_MIN_ID : 4
If anyone knows how I can have it add automatic zeros to the into the query (as it will be different amount of 0s once it gets to 'ABC011') instead of typing them in that would also be very helpful.
Here's how to automatically handle the prepended zeroes.
$sql3 = "SELECT * FROM products WHERE id 'ABC" . sprintf('%03s', $int);

Path report from MySQL

I have a database table that tracks all pageviews which are fired in via a php script. The table looks like this:
rowid (AI)
user_id
page_url
visitor_ip
session_id
I want to be able to query my table to "Show the paths (max 5 pages) visitors take to get to X page within a single session". The output would be a table with a URL in each column, so the path is left to right in the order they visited pages with the same session_id ending with a certain page.
Any clue? I've been looking for a reporting tool to help me build these segments but I'm not coming up with anything so I'm trying to see if there is a way to just query it. I'd like to avoid turning to some other tool for collection and just query my DB if I can.
Does something like this give you what you want (warning - untested):
select group_concat(page_url order by rowid separator '->'),session_id
from pageviews group by session_id
?
One idea is to use correlated subqueries in the select list.
If I understood the specification, the argument(parameter) to the query will be a specific `page_url`, given as "X" in the specification.
The outer query will retrieve the rows for that page_url. The subqueries in the SELECT list will get the previous page_url in the session. (We don't see a datetime/timestamp, so we will need to depend on values of `rowid` increasing for subsequent page views (i.e. previous page views will have a "lower" value of `row_id`.
Something like this:
SELECT ( SELECT p5.page_url
FROM pageviews p5
WHERE p5.session_id = t.session_id
AND p5.rowid < t.rowid
ORDER BY p5.rowid DESC
LIMIT 4,1
) AS back_5_page_url
, ( SELECT p4.page_url
FROM pageviews p4
WHERE p4.session_id = t.session_id
AND p4.rowid < t.rowid
ORDER BY p4.rowid DESC
LIMIT 3,1
) AS back_4_page_url
, ( SELECT p3.page_url
FROM pageviews p3
WHERE p3.session_id = t.session_id
AND p3.rowid < t.rowid
ORDER BY p3.rowid DESC
LIMIT 2,1
) AS back_3_page_url
, ( SELECT p2.page_url
FROM pageviews p2
WHERE p2.session_id = t.session_id
AND p2.rowid < t.rowid
ORDER BY p2.rowid DESC
LIMIT 1,1
) AS back_2_page_url
, ( SELECT p1.page_url
FROM pageviews p5
WHERE p1.session_id = t.session_id
AND p1.rowid < t.rowid
ORDER BY p1.rowid DESC
LIMIT 0,1
) AS back_1_page_url
, t.page_url
, t.session_id
, t.row_id
FROM pageviews t
WHERE t.page_url = 'X'
Those subqueries are going to be executed for each row returned by the outer query, so this could eat our lunch in terms of performance. If no suitable indexes are available, it's going to eat our lunch box too.
For the subqueries, we are going to want an index...
ON pageviews (session_id, row_id, page_url)
The outer query will benefit from an index ...
ON pageviews (page_url, row_id, session_id)
As an idea for the start of a different approach, if we were getting the path to every page_url, and not just a specific one...
SET group_concat_max_len = 524288 ;
SELECT t.session_id
, t.page_url
, SUBSTRING_INDEX(
GROUP_CONCAT(t.page_url SEPARATOR '\t' ORDER BY t.rowid DESC)
,'\t',6) AS `last_5_pages`
FROM pageviews t
GROUP
BY t.session_id
, t.page_url
HAVING t.page_url = 'X'
This assumes that the page_url will not contain a tab (0x09) character.
The last_5_pages column would be a tab-delimited list of page_url, the most recent page view first, followed by the previously viewed page_url, etc.
Getting those split out as individual columns would be more work, wrapping that query in an inline view and some combination of SUBSTRING_INDEX, possibly REVERSE, and a function to count the number of page_url in the list... that gets kind of nasty to do in SQL. If I went this approach, I'd prefer to handle parsing out the page_url from the tab delimited list in the client.
Here is what I ended up doing - worked great.
<?php
require_once 'init.php';
// ----------------- PAGE PATH REPORT
$html = "<table>";
$html .= "<tr><th align='left'>PAGE PATHS HITTING GOAL.PHP</th></tr>";
$paths = array();
$sql = "SELECT cookie_uid, page_url FROM pageviews ORDER BY rowid";
$result = mysqli_query($conn, $sql);
$got_rows = mysqli_num_rows($result);
if ($got_rows) {
while ($row = mysqli_fetch_array($result)) {
// Create an array for the cookie_uid if it doesn't exist yet
if ( ! array_key_exists($row['cookie_uid'], $paths) || ! is_array($paths[$row['cookie_uid']])) {
$paths[$row['cookie_uid']] = [];
}
// Add to the array now that we know it exists
array_push($paths[$row['cookie_uid']], $row['page_url']);
}
foreach ($paths as $session => $page) {
$html .= "<tr>";
$html .= '<td>' . implode(' ---> ', $page) . "</td>";
$html .= "</tr>";
}
} else {
$html .= '<td colspan="2">No results</td>' . "";
}
$html .= "</table>";
echo $html;
if (!mysqli_query($conn,$sql)) {
die('Error: ' . mysqli_error($conn));
}
// ----------------- ALL PAGES REPORT
echo "</br></br>";
echo "<tbody><table>";
echo "<tr><th align='left'>UNIQUE PAGES</th></tr>";
$sql = "SELECT distinct page_url FROM pageviews";
$allpages = mysqli_query($conn, $sql);
foreach ($allpages as $page){
echo "<tr>";
echo "<td>" . $page['page_url'] . "</td>";
echo "</tr>";
}
echo "</tbody></table>";
mysqli_close($conn);
error_reporting(E_ALL);
?>
That gives me this:
/analytics/testpage.php ---> /analytics/testpage2.php ---> /analytics/goal.php

Can I change values in a SQL array in PHP and resort?

I have a SELECT statement that pulls a limited number of items based on the value of one of the fields. (ie ORDER BY rate LIMIT 15).
However, I need to do some comparisons that and change the value of rate, and subsequently could alter the results that I want.
I could pull everything (without the LIMIT), alter the rate, re-sort, and then just process the number that I need. However, I don't know if it's possible to alter values in a php result array. I'm using:
$query_raw = "SELECT dl.dragon_list_id, dl.dragon_id, dl.dragon_name, dl.dragon_level, d.type, d.opposite, d.image, dr.dragon_earn_rate
FROM dragon_list dl
LEFT JOIN dragons d ON d.dragon_id = dl.dragon_id
LEFT JOIN dragon_rates dr ON dr.dragon_id = dl.dragon_id
AND dr.dragon_level = dl.dragon_level
WHERE dl.dragon_id IN (
SELECT dragon_id
FROM dragon_elements
WHERE element_id = 3
)
AND dl.dragon_list_id NOT IN (
SELECT dh.dragon_list_id
FROM dragon_to_habitat dh, dragon_list dl
WHERE dl.user_id = 1
AND dh.dragon_list_id = dl.dragon_list_id
AND dl.is_deleted = 0
)
AND dl.user_id = " . $userid . "
AND dl.is_deleted = 0
ORDER BY dr.dragon_earn_rate DESC, dl.dragon_name
LIMIT 15;";
$query = mysqli_query($link, $query_raw);
if (!$query) {
echo "DB Error, could not query the database\n";
echo 'MySQL Error: ' . mysqli_error($link);
exit;
}
$d = mysqli_fetch_array($d_query);
Well, after a lot of research and some trial and error I found my answers....
Yes, I CAN alter the result rows using something like:
$result['field'] = $newvalue;
I also learned I could reset the pointer by using:
mysqli_data_seek($d_query,0);
However, when I reset the counter, I lost the changes I made. So ultimately, I'm still a little stuck, but individually I had the answers.

MySQL Search by Relevance of all fields

I am sure this is possible but I think it maybe just very complex to write. I want to search every field by:
='SearchTerm'
then
Like %SearchTerm
then
like SearchTerm%
and finally
like %SearchTerm%. I want to run this on every field in my table which there is around 30 or 40. Is there an easy way to run this over multiple fields or will I have to declare every single one?
I think I have seen a query before where different matches between %query %query% etc are ranked by assigning an integer value and then ordering by this. Would that be possible on a query like this?
Any advice and help in the right direction is much appreciated.
You should use fulltext indexing on the fields you want searched and use MATCH AGAINST instead of LIKE %%. It's much faster and returns results based on relevancy. More info here:
Mysql match...against vs. simple like "%term%"
I do something very similar to what you're describing (in php and mysql)
Here's my code:
$search = trim($_GET["search"]);
$searches = explode(" ",$search);
$sql = "SELECT *,wordmatch+descmatch+usagematch+bymatch as `match` FROM (SELECT id,word,LEFT(description,100)as description,
IFNULL((SELECT sum(vote)
FROM vote v
WHERE v.definition_id = d.id),0) as votecount,
";
$sqlword = "";
$sqldesc = "";
$sqlusage = "";
$sqlby = "";
foreach ($searches as $value) {
$value = mysqli_real_escape_string($con,$value);
$sqlword = $sqlword . "+ IFNULL(ROUND((LENGTH(word) - LENGTH(REPLACE(UPPER(word), UPPER('$value'), '')))/LENGTH('$value')),0)";
$sqldesc = $sqldesc . "+ IFNULL(ROUND((LENGTH(description) - LENGTH(REPLACE(UPPER(description), UPPER('$value'), '')))/LENGTH('$value')),0)";
$sqlusage = $sqlusage . "+ IFNULL(ROUND((LENGTH(`usage`) - LENGTH(REPLACE(UPPER(`usage`), UPPER('$value'), '')))/LENGTH('$value')),0)";
$sqlby = $sqlby . "+ IFNULL(ROUND((LENGTH(`by`) - LENGTH(REPLACE(UPPER(`by`), UPPER('$value'), '')))/LENGTH('$value')),0)";
}
$sql = $sql . $sqlword ." as wordmatch,"
. $sqldesc ." as descmatch,"
. $sqlusage ." as usagematch,"
. $sqlby ." as bymatch
FROM definition d
HAVING (wordmatch > 0 OR descmatch > 0 OR usagematch > 0 OR bymatch > 0)
ORDER BY
wordmatch DESC,
descmatch DESC,
usagematch DESC,
bymatch DESC,
votecount DESC)T1";
$queries[] = $sql;
$result = mysqli_query($con,$sql);
You can see this at work http://unurbandictionary.comule.com/view_search.php?search=George+Miley+Cyrus this is when I search for "George Miley Cyrus"
What it does is it explodes the search string to find each word and returns the number of occurences of each word in each of my column, and then i do an ORDER BY to have relevance (priority) to come back first. So in my case word field has the highest relevance, then description field, then usage field, then by field.
Before this version of my code I was using LIKE but it didn't give me a count of occurences, since I want the row with the most occurences of my search word to return first before other rows.
You should really have some sort of id to select the rows in your table.
You should have put a column with
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
Then you could use
SELECT * FROM table WHERE column1 LIKE "%SearchTerm%" AND id BETWEEN 1 AND 40

Categories